diff --git a/.travis.yml b/.travis.yml index 17cd93a..ffafab2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,4 +19,4 @@ matrix: - os: linux compiler: clang - os: osx - osx_image: xcode8.3 + osx_image: xcode10.1 diff --git a/ci-scripts/osx/travis-build.sh b/ci-scripts/osx/travis-build.sh index d5277b9..3dd943e 100644 --- a/ci-scripts/osx/travis-build.sh +++ b/ci-scripts/osx/travis-build.sh @@ -1,6 +1,6 @@ #!/bin/bash pushd thirdparty/tiff-4.0.3 -./configure && make +./configure --disable-lzma && make popd cd toonz && mkdir build && cd build QTVERSION=`ls /usr/local/Cellar/qt` diff --git a/stuff/config/current.txt b/stuff/config/current.txt index a6cd128..e8ac97b 100644 --- a/stuff/config/current.txt +++ b/stuff/config/current.txt @@ -1272,6 +1272,20 @@ "STD_iwa_TextFx.boxColor" "Box Color" "STD_iwa_TextFx.showBorder" "Show Border" + "STD_iwa_CorridorGradientFx" "Corridor Gradient Iwa" + "STD_iwa_CorridorGradientFx.shape" "Shape" + "STD_iwa_CorridorGradientFx.curveType" "Type" + "STD_iwa_CorridorGradientFx.bottom_left_in" "Bottom Left In" + "STD_iwa_CorridorGradientFx.bottom_left_out" "Bottom Left Out" + "STD_iwa_CorridorGradientFx.bottom_right_in" "Bottom Right In" + "STD_iwa_CorridorGradientFx.bottom_right_out" "Bottom Right Out" + "STD_iwa_CorridorGradientFx.top_right_in" "Top Right In" + "STD_iwa_CorridorGradientFx.top_right_out" "Top Right Out" + "STD_iwa_CorridorGradientFx.top_left_in" "Top Left In" + "STD_iwa_CorridorGradientFx.top_left_out" "Top Left Out" + "STD_iwa_CorridorGradientFx.inner_color" "Inner Color" + "STD_iwa_CorridorGradientFx.outer_color" "Outer Color" + STD_iwa_TiledParticlesFx "Tiled Particles Iwa" diff --git a/stuff/profiles/layouts/fxs/STD_iwa_CorridorGradientFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_CorridorGradientFx.xml new file mode 100644 index 0000000..5258f74 --- /dev/null +++ b/stuff/profiles/layouts/fxs/STD_iwa_CorridorGradientFx.xml @@ -0,0 +1,18 @@ + + + shape + curveType + + bottom_left_in + bottom_right_in + top_left_in + top_right_in + inner_color + + bottom_left_out + bottom_right_out + top_left_out + top_right_out + outer_color + + diff --git a/stuff/profiles/layouts/fxs/fxs.lst b/stuff/profiles/layouts/fxs/fxs.lst index b7c1e33..ca26b7c 100644 --- a/stuff/profiles/layouts/fxs/fxs.lst +++ b/stuff/profiles/layouts/fxs/fxs.lst @@ -44,6 +44,7 @@ STD_radialGradientFx STD_spiralFx STD_squareGradientFx + STD_iwa_CorridorGradientFx STD_iwa_AdjustExposureFx diff --git a/toonz/sources/common/tfx/tfx.cpp b/toonz/sources/common/tfx/tfx.cpp index 2b94fdc..ea984c3 100644 --- a/toonz/sources/common/tfx/tfx.cpp +++ b/toonz/sources/common/tfx/tfx.cpp @@ -703,11 +703,18 @@ void TFx::setNewIdentifier() { m_imp->m_id = ++m_imp->m_nextId; } void TFx::loadData(TIStream &is) { std::string tagName; VersionNumber tnzVersion = is.getVersion(); - + // Prevent to load "params" tag under "super" tag on saving macro fx. + // For now "params" tag is no longer saved under "super" tag. + // This is for keeping compatibility with older versions. + bool isInSuperTag = (is.getCurrentTagName() == "super"); QList groupIds; QList groupNames; while (is.openChild(tagName)) { if (tagName == "params") { + if (isInSuperTag) { // skip loading "params" tag under "super" tag + is.skipCurrentTag(); + continue; + } while (!is.eos()) { std::string paramName; while (is.openChild(paramName)) { @@ -829,29 +836,36 @@ void TFx::loadData(TIStream &is) { //-------------------------------------------------- void TFx::saveData(TOStream &os) { + // Prevent to save "params" tag under "super" tag on saving macro fx. + // Parameters for macro fx are saved in "nodes" tag and corrected upon + // loading. Therefore, "params" tag is not needed and even causes crash if + // macrofx contains CurveFx (See the issue #2424) + bool isInSuperTag = (os.getCurrentTagName() == "super"); TFx *linkedSetRoot = this; if (m_imp->m_next != m_imp) { TFxImp *imp = m_imp->m_next; int guard = 0; while (guard++ < 1000 && imp != m_imp) { if (imp->m_fx < linkedSetRoot) linkedSetRoot = imp->m_fx; - imp = imp->m_next; + imp = imp->m_next; } assert(imp == m_imp); assert(linkedSetRoot); } if (linkedSetRoot == this) { - os.openChild("params"); - for (int i = 0; i < getParams()->getParamCount(); i++) { - std::string paramName = getParams()->getParamName(i); - const TParamVar *paramVar = getParams()->getParamVar(i); - // skip saving for the obsolete parameters - if (paramVar->isObsolete()) continue; - os.openChild(paramName); - paramVar->getParam()->saveData(os); + if (!isInSuperTag) { // skip saving "params" tag under "super" tag + os.openChild("params"); + for (int i = 0; i < getParams()->getParamCount(); i++) { + std::string paramName = getParams()->getParamName(i); + const TParamVar *paramVar = getParams()->getParamVar(i); + // skip saving for the obsolete parameters + if (paramVar->isObsolete()) continue; + os.openChild(paramName); + paramVar->getParam()->saveData(os); + os.closeChild(); + } os.closeChild(); } - os.closeChild(); } else { os.openChild("paramsLinkedTo"); os << linkedSetRoot; diff --git a/toonz/sources/common/tstream/tstream.cpp b/toonz/sources/common/tstream/tstream.cpp index 7eb57fb..6311924 100644 --- a/toonz/sources/common/tstream/tstream.cpp +++ b/toonz/sources/common/tstream/tstream.cpp @@ -470,7 +470,7 @@ TOStream &TOStream::operator<<(const TPixel64 &v) { void TOStream::cr() { *(m_imp->m_os) << endl; - for (int i = 0; i < m_imp->m_tab; i++) *(m_imp->m_os) << " "; + for (int i = 0; i < m_imp->m_tab; i++) *(m_imp->m_os) << " "; m_imp->m_justStarted = false; } @@ -587,6 +587,10 @@ bool TOStream::checkStatus() const { return m_imp->m_os->rdstate() == ios_base::goodbit; } +std::string TOStream::getCurrentTagName() { + return (m_imp->m_tagStack.empty()) ? "" : m_imp->m_tagStack.back(); +} + //=============================================================== /*! This class contains TIStream's attributes. @@ -1118,8 +1122,8 @@ TIStream &TIStream::operator>>(TPersist *&v) { m_imp->m_currentTag = StreamTag(); string tagName = tag.m_name; std::map::iterator it; - int id = -1; - it = tag.m_attributes.find("id"); + int id = -1; + it = tag.m_attributes.find("id"); if (it != tag.m_attributes.end()) id = atoi(it->second.c_str()); // cout << "tagname = " << tagName << " id = " << id << endl; @@ -1277,3 +1281,7 @@ void TIStream::setVersion(const VersionNumber &version) { //--------------------------------------------------------------- void TIStream::skipCurrentTag() { m_imp->skipCurrentTag(); } + +//--------------------------------------------------------------- + +std::string TIStream::getCurrentTagName() { return m_imp->m_tagStack.back(); } \ No newline at end of file diff --git a/toonz/sources/include/tools/cursors.h b/toonz/sources/include/tools/cursors.h index 44f0e49..2988e23 100644 --- a/toonz/sources/include/tools/cursors.h +++ b/toonz/sources/include/tools/cursors.h @@ -32,6 +32,7 @@ enum { MagnetCursor, PanCursor, PickerCursor, + PointingHandCursor, PumpCursor, RotCursor, RotTopLeft, diff --git a/toonz/sources/include/toonz/txsheet.h b/toonz/sources/include/toonz/txsheet.h index 6dbced4..4fc2a8d 100644 --- a/toonz/sources/include/toonz/txsheet.h +++ b/toonz/sources/include/toonz/txsheet.h @@ -391,13 +391,13 @@ public: cells will be inserted by shifting the other down. */ void stepCells(int r0, int c0, int r1, int c1, int type); - /*! For each sequenze of frame with same number, contained in rect delimited + /*! For each sequence of frame with same number, contained in rect delimited by first row \b \e r0, last row \b \e r1 and first column \b \e c0, a frame with same number is inserted. */ void increaseStepCells(int r0, int c0, int &r1, int c1); /*! -For each sequenze of frame with same number, contained in rect delimited by +For each sequence of frame with same number, contained in rect delimited by first row \b \e r0, last row \b \e r1 and first column \b \e c0, a frame with same number is removed. */ @@ -405,7 +405,7 @@ first row \b \e r0, last row \b \e r1 and /*! The cells, contained in rect delimited by first row \b \e r0, last row \b \e r1 and - first column \b \e c0, are resetted in order to have no sequential + first column \b \e c0, are reset in order to have no sequential frame duplication. */ void resetStepCells(int r0, int c0, int r1, int c1); diff --git a/toonz/sources/include/toonzqt/doublefield.h b/toonz/sources/include/toonzqt/doublefield.h index 2ad8730..df82aca 100644 --- a/toonz/sources/include/toonzqt/doublefield.h +++ b/toonz/sources/include/toonzqt/doublefield.h @@ -102,12 +102,20 @@ onSliderChanged(int value), class DVAPI DoubleValueField : public QWidget { Q_OBJECT + bool m_isLinearSlider; + protected: RollerField *m_roller; DoubleValueLineEdit *m_lineEdit; QSlider *m_slider; QWidget *m_spaceWidget; + void setLinearSlider(bool linear) { m_isLinearSlider = linear; } + +private: + double pos2value(int x) const; + int value2pos(double v) const; + public: DoubleValueField(QWidget *parent, DoubleValueLineEdit *lineEdit); ~DoubleValueField() {} @@ -158,7 +166,7 @@ signals: void valueChanged(bool); /*! This signal is emitted only when users edited the value by hand -*/ + */ void valueEditedByHand(); }; diff --git a/toonz/sources/include/toonzqt/doublepairfield.h b/toonz/sources/include/toonzqt/doublepairfield.h index 7220cb0..7d8799d 100644 --- a/toonz/sources/include/toonzqt/doublepairfield.h +++ b/toonz/sources/include/toonzqt/doublepairfield.h @@ -102,6 +102,8 @@ protected: bool m_isMaxRangeLimited; + bool m_isLinear; + public: DoubleValuePairField(QWidget *parent, bool isMaxRangeLimited, DoubleValueLineEdit *leftLineEdit, @@ -174,6 +176,7 @@ protected: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; + void setLinearSlider(bool linear) { m_isLinear = linear; } protected slots: /*! Set current left value to value in left text field; if necessary, if left value is greater than right, change also current right value. diff --git a/toonz/sources/include/toonzqt/intfield.h b/toonz/sources/include/toonzqt/intfield.h index 7dc4577..61d14b2 100644 --- a/toonz/sources/include/toonzqt/intfield.h +++ b/toonz/sources/include/toonzqt/intfield.h @@ -167,6 +167,7 @@ class DVAPI IntField : public QWidget { IntLineEdit *m_lineEdit; QSlider *m_slider; bool m_isMaxRangeLimited; + bool m_isLinearSlider; public: IntField(QWidget *parent = 0, bool isMaxRangeLimited = true, @@ -205,6 +206,13 @@ public: void setLineEditBackgroundColor(QColor color); +protected: + void setLinearSlider(bool linear) { m_isLinearSlider = linear; } + +private: + int pos2value(int x) const; + int value2pos(int v) const; + protected slots: /*! Set to value the text field. If text field value is different from \b value diff --git a/toonz/sources/include/toonzqt/intpairfield.h b/toonz/sources/include/toonzqt/intpairfield.h index c2fffa4..1bc282c 100644 --- a/toonz/sources/include/toonzqt/intpairfield.h +++ b/toonz/sources/include/toonzqt/intpairfield.h @@ -112,6 +112,8 @@ class DVAPI IntPairField : public QWidget { bool m_isMaxRangeLimited; + bool m_isLinear; + public: IntPairField(QWidget *parent = 0, bool isMaxRangeLimited = true); ~IntPairField() {} @@ -166,9 +168,9 @@ public: protected: /*! Return value corresponding \b x position. */ - double pos2value(int x) const; + int pos2value(int x) const; /*! Return x position corresponding \b value. */ - int value2pos(double v) const; + int value2pos(int v) const; /*! Set current value to \b value. Set left or right value, or both, to value depending on @@ -182,6 +184,7 @@ protected: void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; + void setLinearSlider(bool linear) { m_isLinear = linear; } protected slots: /*! Set current left value to value in left text field; if necessary, if left value is greater than right, change also current right value. diff --git a/toonz/sources/include/tproperty.h b/toonz/sources/include/tproperty.h index c0af682..1142e2f 100644 --- a/toonz/sources/include/tproperty.h +++ b/toonz/sources/include/tproperty.h @@ -112,7 +112,8 @@ public: : TProperty(name) , m_range(minValue, maxValue) , m_value(minValue) - , m_isMaxRangeLimited(isMaxRangeLimited) { + , m_isMaxRangeLimited(isMaxRangeLimited) + , m_isLinearSlider(true) { setValue(value); } @@ -138,10 +139,14 @@ public: bool isMaxRangeLimited() const { return m_isMaxRangeLimited; } + void setNonLinearSlider() { m_isLinearSlider = false; } + bool isLinearSlider() { return m_isLinearSlider; } + private: Range m_range; T m_value; bool m_isMaxRangeLimited; + bool m_isLinearSlider; }; //--------------------------------------------------------- @@ -160,7 +165,8 @@ public: double v0, double v1, bool isMaxRangeLimited = true) : TProperty(name) , m_range(Range(minValue, maxValue)) - , m_isMaxRangeLimited(isMaxRangeLimited) { + , m_isMaxRangeLimited(isMaxRangeLimited) + , m_isLinearSlider(true) { setValue(Value(v0, v1)); } @@ -184,10 +190,14 @@ public: } void accept(Visitor &v) override { v.visit(this); }; + void setNonLinearSlider() { m_isLinearSlider = false; } + bool isLinearSlider() { return m_isLinearSlider; } + private: Range m_range; Value m_value; bool m_isMaxRangeLimited; + bool m_isLinearSlider; }; //--------------------------------------------------------- @@ -201,7 +211,8 @@ public: bool isMaxRangeLimited = true) : TProperty(name) , m_range(minValue, maxValue) - , m_isMaxRangeLimited(isMaxRangeLimited) { + , m_isMaxRangeLimited(isMaxRangeLimited) + , m_isLinearSlider(true) { setValue(Value(v0, v1)); } @@ -225,10 +236,14 @@ public: } void accept(Visitor &v) override { v.visit(this); }; + void setNonLinearSlider() { m_isLinearSlider = false; } + bool isLinearSlider() { return m_isLinearSlider; } + private: Range m_range; Value m_value; bool m_isMaxRangeLimited; + bool m_isLinearSlider; }; //--------------------------------------------------------- diff --git a/toonz/sources/include/tstopwatch.h b/toonz/sources/include/tstopwatch.h index 1669c34..2b25073 100644 --- a/toonz/sources/include/tstopwatch.h +++ b/toonz/sources/include/tstopwatch.h @@ -86,7 +86,7 @@ public: /*!Returns the number of milliseconds that have elapsed in all the start()-stop() intervals since -the stopWatch was resetted up to the getTotalTime() call. The method can be +the stopWatch was reset up to the getTotalTime() call. The method can be called during a start()-stop() interval */ TUINT32 getTotalTime(); diff --git a/toonz/sources/include/tstream.h b/toonz/sources/include/tstream.h index 146ca50..27d5367 100644 --- a/toonz/sources/include/tstream.h +++ b/toonz/sources/include/tstream.h @@ -155,6 +155,8 @@ reimplementation of the TPersist::loadData() function. void skipCurrentTag(); //!< Silently ignores the content of currently opened //! tag up to its end. + std::string getCurrentTagName(); + private: // Not copyable TIStream(const TIStream &); //!< Not implemented @@ -266,6 +268,8 @@ checking the status. */ bool checkStatus() const; //!< \b Flushes the stream and checks its validity. + std::string getCurrentTagName(); + private: // Not copyable TOStream(const TOStream &) = delete; //!< Not implemented diff --git a/toonz/sources/stdfx/CMakeLists.txt b/toonz/sources/stdfx/CMakeLists.txt index f0a0017..4aa2aaf 100644 --- a/toonz/sources/stdfx/CMakeLists.txt +++ b/toonz/sources/stdfx/CMakeLists.txt @@ -76,6 +76,7 @@ set(HEADERS iwa_timecodefx.h iwa_bokehreffx.h iwa_textfx.h + iwa_corridorgradientfx.h ) set(SOURCES @@ -258,6 +259,7 @@ set(SOURCES iwa_bokehreffx.cpp iwa_barreldistortfx.cpp iwa_textfx.cpp + iwa_corridorgradientfx.cpp ) set(OBJCSOURCES diff --git a/toonz/sources/stdfx/freedistortfx.cpp b/toonz/sources/stdfx/freedistortfx.cpp index 8e3dfab..45db345 100644 --- a/toonz/sources/stdfx/freedistortfx.cpp +++ b/toonz/sources/stdfx/freedistortfx.cpp @@ -19,7 +19,7 @@ namespace { inline bool myIsEmpty(const TRectD &r) { return r.x0 >= r.x1 || r.y0 >= r.y1; } -} +} // namespace //============================================================================== @@ -415,19 +415,21 @@ void FreeDistortBaseFx::safeTransform(double frame, int port, // ------------------------------------------------------------------------ void FreeDistortBaseFx::getParamUIs(TParamUIConcept *&concepts, int &length) { - concepts = new TParamUIConcept[length = 14]; + concepts = new TParamUIConcept[length = 6]; concepts[0].m_type = TParamUIConcept::QUAD; - concepts[0].m_params.push_back(m_p00_b); - concepts[0].m_params.push_back(m_p10_b); - concepts[0].m_params.push_back(m_p11_b); concepts[0].m_params.push_back(m_p01_b); + concepts[0].m_params.push_back(m_p11_b); + concepts[0].m_params.push_back(m_p10_b); + concepts[0].m_params.push_back(m_p00_b); + concepts[0].m_label = " Src"; concepts[1].m_type = TParamUIConcept::QUAD; - concepts[1].m_params.push_back(m_p00_a); - concepts[1].m_params.push_back(m_p10_a); - concepts[1].m_params.push_back(m_p11_a); concepts[1].m_params.push_back(m_p01_a); + concepts[1].m_params.push_back(m_p11_a); + concepts[1].m_params.push_back(m_p10_a); + concepts[1].m_params.push_back(m_p00_a); + concepts[1].m_label = " Dst"; concepts[2].m_type = TParamUIConcept::VECTOR; concepts[2].m_params.push_back(m_p00_b); @@ -444,38 +446,6 @@ void FreeDistortBaseFx::getParamUIs(TParamUIConcept *&concepts, int &length) { concepts[5].m_type = TParamUIConcept::VECTOR; concepts[5].m_params.push_back(m_p11_b); concepts[5].m_params.push_back(m_p11_a); - - concepts[6].m_type = TParamUIConcept::POINT; - concepts[6].m_label = "Bottom Left Src"; - concepts[6].m_params.push_back(m_p00_b); - - concepts[7].m_type = TParamUIConcept::POINT; - concepts[7].m_label = "Bottom Right Src"; - concepts[7].m_params.push_back(m_p10_b); - - concepts[8].m_type = TParamUIConcept::POINT; - concepts[8].m_label = "Top Left Src"; - concepts[8].m_params.push_back(m_p01_b); - - concepts[9].m_type = TParamUIConcept::POINT; - concepts[9].m_label = "Top Right Src"; - concepts[9].m_params.push_back(m_p11_b); - - concepts[10].m_type = TParamUIConcept::POINT; - concepts[10].m_label = "Bottom Left Dst"; - concepts[10].m_params.push_back(m_p00_a); - - concepts[11].m_type = TParamUIConcept::POINT; - concepts[11].m_label = "Bottom Right Dst"; - concepts[11].m_params.push_back(m_p10_a); - - concepts[12].m_type = TParamUIConcept::POINT; - concepts[12].m_label = "Top Left Dst"; - concepts[12].m_params.push_back(m_p01_a); - - concepts[13].m_type = TParamUIConcept::POINT; - concepts[13].m_label = "Top Right Dst"; - concepts[13].m_params.push_back(m_p11_a); } // ------------------------------------------------------------------------ @@ -672,7 +642,7 @@ void doBlur(TRasterPT &r, double blur0, double blur1, double transp0, r->unlock(); delete[] row; } -} +} // namespace // ------------------------------------------------------------------------ diff --git a/toonz/sources/stdfx/iwa_corridorgradientfx.cpp b/toonz/sources/stdfx/iwa_corridorgradientfx.cpp new file mode 100644 index 0000000..96e826c --- /dev/null +++ b/toonz/sources/stdfx/iwa_corridorgradientfx.cpp @@ -0,0 +1,378 @@ +#include "iwa_corridorgradientfx.h" + +#include "trop.h" +#include "tparamuiconcept.h" +#include "tspectrumparam.h" +#include "gradients.h" + +#include + +#include +#include + +//------------------------------------------------------------ + +Iwa_CorridorGradientFx::Iwa_CorridorGradientFx() + : m_shape(new TIntEnumParam(0, "Quadrangle")) + , m_innerColor(TPixel32::White) + , m_outerColor(TPixel32::Black) + , m_curveType(new TIntEnumParam()) { + for (int inout = 0; inout < 2; inout++) { + double size = (inout == 0) ? 50. : 400.; + std::string inout_str = (inout == 0) ? "_in" : "_out"; + + for (int c = 0; c < 4; c++) { + Qt::Corner corner = (Qt::Corner)c; + TPointD basePos(1, 1); + if (corner == Qt::TopLeftCorner || corner == Qt::BottomLeftCorner) + basePos.x *= -1; + if (corner == Qt::BottomLeftCorner || corner == Qt::BottomRightCorner) + basePos.y *= -1; + + m_points[inout][corner] = basePos * size; + + m_points[inout][corner]->getX()->setMeasureName("fxLength"); + m_points[inout][corner]->getY()->setMeasureName("fxLength"); + + std::string TB_str = + (corner == Qt::TopLeftCorner || corner == Qt::TopRightCorner) + ? "top" + : "bottom"; + std::string LR_str = + (corner == Qt::TopLeftCorner || corner == Qt::BottomLeftCorner) + ? "_left" + : "_right"; + + bindParam(this, TB_str + LR_str + inout_str, m_points[inout][corner]); + } + } + + m_shape->addItem(1, "Circle"); + bindParam(this, "shape", m_shape); + + m_curveType->addItem(EaseInOut, "Ease In-Out"); + m_curveType->addItem(Linear, "Linear"); + m_curveType->addItem(EaseIn, "Ease In"); + m_curveType->addItem(EaseOut, "Ease Out"); + m_curveType->setDefaultValue(Linear); + m_curveType->setValue(Linear); + bindParam(this, "curveType", m_curveType); + + bindParam(this, "inner_color", m_innerColor); + bindParam(this, "outer_color", m_outerColor); +} + +//------------------------------------------------------------ + +bool Iwa_CorridorGradientFx::doGetBBox(double frame, TRectD &bBox, + const TRenderSettings &ri) { + bBox = TConsts::infiniteRectD; + return true; +} + +//------------------------------------------------------------ + +namespace { + +QPointF toQPointF(const TPointD &p) { return QPointF(p.x, p.y); } + +double WedgeProduct(const TPointD v, const TPointD w) { + return v.x * w.y - v.y * w.x; +} + +struct BilinearParam { + TPointD p0, b1, b2, b3; +}; + +//------------------------------------------------------------ + +double getFactor(const TPointD &p, const BilinearParam ¶m, + const GradientCurveType type) { + double t; + TPointD q = p - param.p0; + // Set up quadratic formula + float A = WedgeProduct(param.b2, param.b3); + float B = WedgeProduct(param.b3, q) - WedgeProduct(param.b1, param.b2); + float C = WedgeProduct(param.b1, q); + + // Solve for v + if (std::abs(A) < 0.001) { + // Linear form + t = -C / B; + } else { + // Quadratic form + float discrim = B * B - 4 * A * C; + t = 0.5 * (-B - std::sqrt(discrim)) / A; + } + double factor; + switch (type) { + case Linear: + factor = t; + break; + case EaseIn: + factor = t * t; + break; + case EaseOut: + factor = 1.0 - (1.0 - t) * (1.0 - t); + break; + case EaseInOut: + default: + factor = (-2 * t + 3) * (t * t); + break; + } + return factor; +} + +//------------------------------------------------------------ + +template +void doQuadrangleT(RASTER ras, TDimensionI dim, TPointD pos[2][4], + const TSpectrumT &spectrum, GradientCurveType type) { + auto buildPolygon = [&](QPolygonF &pol, Qt::Corner c1, Qt::Corner c2) { + pol << toQPointF(pos[0][(int)c1]) << toQPointF(pos[1][(int)c1]) + << toQPointF(pos[1][(int)c2]) << toQPointF(pos[0][(int)c2]); + }; + + auto buildBilinearParam = [&](BilinearParam &bp, Qt::Corner c1, + Qt::Corner c2) { + bp.p0 = pos[0][(int)c1]; + bp.b1 = pos[0][(int)c2] - pos[0][(int)c1]; + bp.b2 = pos[1][(int)c1] - pos[0][(int)c1]; + bp.b3 = + pos[0][(int)c1] - pos[0][(int)c2] - pos[1][(int)c1] + pos[1][(int)c2]; + }; + + std::array polygons; + std::array params; + + // Top + buildPolygon(polygons[0], Qt::TopLeftCorner, Qt::TopRightCorner); + buildBilinearParam(params[0], Qt::TopLeftCorner, Qt::TopRightCorner); + // Left + buildPolygon(polygons[1], Qt::BottomLeftCorner, Qt::TopLeftCorner); + buildBilinearParam(params[1], Qt::BottomLeftCorner, Qt::TopLeftCorner); + // Bottom + buildPolygon(polygons[2], Qt::BottomRightCorner, Qt::BottomLeftCorner); + buildBilinearParam(params[2], Qt::BottomRightCorner, Qt::BottomLeftCorner); + // Right + buildPolygon(polygons[3], Qt::TopRightCorner, Qt::BottomRightCorner); + buildBilinearParam(params[3], Qt::TopRightCorner, Qt::BottomRightCorner); + + QPolygonF innerPolygon; + innerPolygon << toQPointF(pos[0][Qt::TopLeftCorner]) + << toQPointF(pos[0][Qt::TopRightCorner]) + << toQPointF(pos[0][Qt::BottomRightCorner]) + << toQPointF(pos[0][Qt::BottomLeftCorner]); + + ras->lock(); + for (int j = 0; j < ras->getLy(); j++) { + PIXEL *pix = ras->pixels(j); + PIXEL *endPix = pix + ras->getLx(); + int i = 0; + while (pix < endPix) { + QPointF p(i, j); + + double factor; + bool found = false; + for (int edge = 0; edge < 4; edge++) { + if (polygons[edge].containsPoint(p, Qt::WindingFill)) { + factor = getFactor(TPointD(i, j), params.at(edge), type); + found = true; + break; + } + } + if (!found) { + if (innerPolygon.containsPoint(p, Qt::WindingFill)) + factor = 0.0; + else + factor = 1.0; + } + + *pix++ = spectrum.getPremultipliedValue(factor); + i++; + } + } + ras->unlock(); +} + +//------------------------------------------------------------ + +template +void doCircleT(RASTER ras, TDimensionI dim, TPointD pos[2][4], + const TSpectrumT &spectrum, GradientCurveType type) { + auto lerp = [](TPointD p1, TPointD p2, double f) { + return p1 * (1 - f) + p2 * f; + }; + auto bilinearPos = [&](TPointD uv, int inout) { + return lerp(lerp(pos[inout][Qt::BottomLeftCorner], + pos[inout][Qt::BottomRightCorner], uv.x), + lerp(pos[inout][Qt::TopLeftCorner], + pos[inout][Qt::TopRightCorner], uv.x), + uv.y); + }; + + const int DIVNUM = 36; + + std::array innerPos; + std::array outerPos; + double tmpRadius = std::sqrt(2.0) / 2.0; + for (int div = 0; div < DIVNUM; div++) { + double angle = 2.0 * M_PI * (double)div / (double)DIVNUM; + // circle position in uv coordinate + TPointD uv(tmpRadius * std::cos(angle) + 0.5, + tmpRadius * std::sin(angle) + 0.5); + // compute inner and outer circle positions by bilinear interpolation + // using uv coordinate values. + innerPos[div] = bilinearPos(uv, 0); + outerPos[div] = bilinearPos(uv, 1); + } + + // - - - - - - - - + + auto buildPolygon = [&](QPolygonF &pol, int id1, int id2) { + pol << toQPointF(innerPos[id2]) << toQPointF(outerPos[id2]) + << toQPointF(outerPos[id1]) << toQPointF(innerPos[id1]); + }; + + auto buildBilinearParam = [&](BilinearParam &bp, int id1, int id2) { + bp.p0 = innerPos[id2]; + bp.b1 = innerPos[id1] - innerPos[id2]; + bp.b2 = outerPos[id2] - innerPos[id2]; + bp.b3 = innerPos[id2] - innerPos[id1] - outerPos[id2] + outerPos[id1]; + }; + std::array polygons; + std::array params; + QPolygonF innerPolygon; + for (int div = 0; div < DIVNUM; div++) { + int next_div = (div == DIVNUM - 1) ? 0 : div + 1; + // create polygon and bilinear parameters for each piece surrounding the + // circle + buildPolygon(polygons[div], div, next_div); + buildBilinearParam(params[div], div, next_div); + // create inner circle polygon + innerPolygon << toQPointF(innerPos[div]); + } + + // - - - ok, ready to render + + ras->lock(); + + for (int j = 0; j < ras->getLy(); j++) { + PIXEL *pix = ras->pixels(j); + PIXEL *endPix = pix + ras->getLx(); + int i = 0; + while (pix < endPix) { + QPointF p(i, j); + double factor; + bool found = false; + for (int div = 0; div < DIVNUM; div++) { + // check if the point is inside of the surrounding pieces + if (polygons[div].containsPoint(p, Qt::WindingFill)) { + // compute factor by invert bilinear interpolation + factor = getFactor(TPointD(i, j), params.at(div), type); + found = true; + break; + } + } + if (!found) { + if (innerPolygon.containsPoint(p, Qt::WindingFill)) + factor = 0.0; + else + factor = 1.0; + } + + *pix++ = spectrum.getPremultipliedValue(factor); + + i++; + } + } + ras->unlock(); +} + +}; // namespace + +//------------------------------------------------------------ + +void Iwa_CorridorGradientFx::doCompute(TTile &tile, double frame, + const TRenderSettings &ri) { + if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) { + throw TRopException("unsupported input pixel type"); + } + + // convert shape position to render region coordinate + TPointD pos[2][4]; + TAffine aff = ri.m_affine; + TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy()); + TPointD dimOffset((float)dimOut.lx / 2.0f, (float)dimOut.ly / 2.0f); + for (int inout = 0; inout < 2; inout++) { + for (int c = 0; c < 4; c++) { + TPointD _point = m_points[inout][c]->getValue(frame); + pos[inout][c] = aff * _point - + (tile.m_pos + tile.getRaster()->getCenterD()) + dimOffset; + } + } + + std::vector colors = { + TSpectrum::ColorKey(0, m_innerColor->getValue(frame)), + TSpectrum::ColorKey(1, m_outerColor->getValue(frame))}; + TSpectrumParamP m_colors = TSpectrumParamP(colors); + + tile.getRaster()->clear(); + TRaster32P outRas32 = (TRaster32P)tile.getRaster(); + TRaster64P outRas64 = (TRaster64P)tile.getRaster(); + if (m_shape->getValue() == 0) { // Quadrangle + if (outRas32) + doQuadrangleT( + outRas32, dimOut, pos, m_colors->getValue(frame), + (GradientCurveType)m_curveType->getValue()); + else if (outRas64) + doQuadrangleT( + outRas64, dimOut, pos, m_colors->getValue64(frame), + (GradientCurveType)m_curveType->getValue()); + } else { // m_shape == 1 : Circle + if (outRas32) + doCircleT( + outRas32, dimOut, pos, m_colors->getValue(frame), + (GradientCurveType)m_curveType->getValue()); + else if (outRas64) + doCircleT( + outRas64, dimOut, pos, m_colors->getValue64(frame), + (GradientCurveType)m_curveType->getValue()); + } +} + +//------------------------------------------------------------ + +void Iwa_CorridorGradientFx::getParamUIs(TParamUIConcept *&concepts, + int &length) { + concepts = new TParamUIConcept[length = 6]; + + int vectorUiIdOffset = 2; + + std::array loopIds{Qt::TopLeftCorner, Qt::TopRightCorner, + Qt::BottomRightCorner, + Qt::BottomLeftCorner}; + + for (int inout = 0; inout < 2; inout++) { + concepts[inout].m_type = TParamUIConcept::QUAD; + + for (int c = 0; c < 4; c++) { + Qt::Corner corner = loopIds[c]; + + // quad ui + concepts[inout].m_params.push_back(m_points[inout][(int)corner]); + concepts[inout].m_label = (inout == 0) ? " In" : " Out"; + + // vector ui + if (inout == 0) + concepts[vectorUiIdOffset + (int)corner].m_type = + TParamUIConcept::VECTOR; + concepts[vectorUiIdOffset + (int)corner].m_params.push_back( + m_points[inout][(int)corner]); + } + } +} + +//------------------------------------------------------------ + +FX_PLUGIN_IDENTIFIER(Iwa_CorridorGradientFx, "iwa_CorridorGradientFx"); diff --git a/toonz/sources/stdfx/iwa_corridorgradientfx.h b/toonz/sources/stdfx/iwa_corridorgradientfx.h new file mode 100644 index 0000000..c16ecc3 --- /dev/null +++ b/toonz/sources/stdfx/iwa_corridorgradientfx.h @@ -0,0 +1,31 @@ +#pragma once +#ifndef IWA_CORRIDORGRADIENTFX_H +#define IWA_CORRIDORGRADIENTFX_H + +#include "tfxparam.h" +#include "stdfx.h" +#include "tparamset.h" + +class Iwa_CorridorGradientFx final : public TStandardZeraryFx { + FX_PLUGIN_DECLARATION(Iwa_CorridorGradientFx) + + TIntEnumParamP m_shape; + TIntEnumParamP m_curveType; + TPointParamP m_points[2][4]; // [in/out][Qt::Corner] + + TPixelParamP m_innerColor; + TPixelParamP m_outerColor; + +public: + Iwa_CorridorGradientFx(); + + bool canHandle(const TRenderSettings &info, double frame) override { + return true; + } + bool doGetBBox(double frame, TRectD &bBox, + const TRenderSettings &ri) override; + void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override; + void getParamUIs(TParamUIConcept *&concepts, int &length) override; +}; + +#endif \ No newline at end of file diff --git a/toonz/sources/tnztools/Resources/pointing_hand.png b/toonz/sources/tnztools/Resources/pointing_hand.png new file mode 100644 index 0000000..d3de175 Binary files /dev/null and b/toonz/sources/tnztools/Resources/pointing_hand.png differ diff --git a/toonz/sources/tnztools/cursormanager.cpp b/toonz/sources/tnztools/cursormanager.cpp index 40a56c7..48cf7fb 100644 --- a/toonz/sources/tnztools/cursormanager.cpp +++ b/toonz/sources/tnztools/cursormanager.cpp @@ -54,6 +54,8 @@ const struct { {ToolCursor::PickerCursorAreaBase, "picker_style", 7, 22, true}, {ToolCursor::PickerCursor, "picker_style", 7, 22, true}, + {ToolCursor::PointingHandCursor, "pointing_hand", 13, 4, true}, + {ToolCursor::PumpCursor, "pump", 16, 23, false}, {ToolCursor::RotCursor, "rot", 15, 15, false}, {ToolCursor::RotTopLeft, "rot_top_left", 15, 15, false}, diff --git a/toonz/sources/tnztools/edittoolgadgets.cpp b/toonz/sources/tnztools/edittoolgadgets.cpp index 3fb6f5d..c3c30ee 100644 --- a/toonz/sources/tnztools/edittoolgadgets.cpp +++ b/toonz/sources/tnztools/edittoolgadgets.cpp @@ -30,8 +30,13 @@ int getDevPixRatio() { static int devPixRatio = QApplication::desktop()->devicePixelRatio(); return devPixRatio; } + +TPointD hadamard(const TPointD &v1, const TPointD &v2) { + return TPointD(v1.x * v2.x, v1.y * v2.y); } +} // namespace + //************************************************************************************* // FxGadgetUndo definition //************************************************************************************* @@ -131,13 +136,14 @@ public: // FxGadget implementation //************************************************************************************* -FxGadget::FxGadget(FxGadgetController *controller) +FxGadget::FxGadget(FxGadgetController *controller, int handleCount) : m_id(-1) - , m_selected(false) + , m_selected(-1) , m_controller(controller) , m_pixelSize(1) , m_undo(0) - , m_scaleFactor(1) { + , m_scaleFactor(1) + , m_handleCount(handleCount) { controller->assignId(this); } @@ -592,7 +598,7 @@ void DiamondFxGadget::draw(bool picking) { //--------------------------------------------------------------------------- void DiamondFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &) { - double sz = fabs(pos.x) + fabs(pos.y); + double sz = fabs(pos.x) + fabs(pos.y); if (sz < 0.1) sz = 0.1; setValue(m_param, sz); } @@ -841,12 +847,11 @@ public: class VectorFxGadget final : public FxGadget { TPointParamP m_pa, m_pb; - int m_selected; public: VectorFxGadget(FxGadgetController *controller, const TPointParamP &pa, const TPointParamP &pb) - : FxGadget(controller), m_pa(pa), m_pb(pb), m_selected(0) { + : FxGadget(controller), m_pa(pa), m_pb(pb) { addParam(pa->getX()); addParam(pa->getY()); addParam(pb->getX()); @@ -859,7 +864,7 @@ public: glColor3dv(m_selectedColor); else glColor3d(0, 0, 1); - glPushName(getId()); + // glPushName(getId()); double pixelSize = getPixelSize(); TPointD pa = getValue(m_pa); TPointD pb = getValue(m_pb); @@ -882,11 +887,11 @@ public: } tglDrawSegment(pbb, pbb - u * a + v * b); tglDrawSegment(pbb, pbb - u * a - v * b); - drawDot(pa); - drawDot(pb); - } else - drawDot(pa); - glPopName(); + // drawDot(pa); + // drawDot(pb); + } // else + // drawDot(pa); + // glPopName(); } void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {} @@ -897,53 +902,269 @@ public: //============================================================================= class QuadFxGadget final : public FxGadget { - TPointParamP m_pa, m_pb, m_pc, m_pd; + TPointParamP m_TL, m_TR, m_BR, m_BL; + + enum HANDLE { + Body = 0, + TopLeft, + TopRight, + BottomRight, + BottomLeft, + TopEdge, + RightEdge, + BottomEdge, + LeftEdge, + None + } m_handle = None; + + TPointD m_pivot; + TPointD m_dragStartPos; + TPointD m_startTL, m_startTR, m_startBR, m_startBL; public: - QuadFxGadget(FxGadgetController *controller, const TPointParamP &pa, - const TPointParamP &pb, const TPointParamP &pc, - const TPointParamP &pd) - : FxGadget(controller), m_pa(pa), m_pb(pb), m_pc(pc), m_pd(pd) { - addParam(pa->getX()); - addParam(pa->getY()); - addParam(pb->getX()); - addParam(pb->getY()); - addParam(pc->getX()); - addParam(pc->getY()); - addParam(pd->getX()); - addParam(pd->getY()); + QuadFxGadget(FxGadgetController *controller, const TPointParamP &topLeft, + const TPointParamP &topRight, const TPointParamP &bottomRight, + const TPointParamP &bottomLeft) + : FxGadget(controller, 9) + , m_TL(topLeft) + , m_TR(topRight) + , m_BR(bottomRight) + , m_BL(bottomLeft) { + addParam(topLeft->getX()); + addParam(topLeft->getY()); + addParam(topRight->getX()); + addParam(topRight->getY()); + addParam(bottomRight->getX()); + addParam(bottomRight->getY()); + addParam(bottomLeft->getX()); + addParam(bottomLeft->getY()); } void draw(bool picking) override { + int idBase = getId(); + + auto setColorById = [&](int id) { + if (isSelected(id)) + glColor3dv(m_selectedColor); + else + glColor3d(0, 0, 1); + }; + + auto id2Str = [](const HANDLE handleId) -> std::string { + switch (handleId) { + case TopLeft: + return "Top Left"; + case TopRight: + return "Top Right"; + case BottomRight: + return "Bottom Right"; + case BottomLeft: + return "Bottom Left"; + default: + return ""; + } + }; + + auto drawPoint = [&](const TPointD &pos, int id) { + setColorById(id); + glPushName(idBase + id); + double unit = getPixelSize(); + glPushMatrix(); + glTranslated(pos.x, pos.y, 0); + double r = unit * 3; + tglDrawRect(-r, -r, r, r); + glPopMatrix(); + glPopName(); + + if (isSelected(id) && id >= TopLeft && id <= BottomLeft) { + drawTooltip(pos + TPointD(7, 3) * unit, + id2Str((HANDLE)id) + getLabel()); + } + }; + setPixelSize(); - if (isSelected()) - glColor3dv(m_selectedColor); - else - glColor3d(0, 0, 1); - // glPushName(getId()); - double pixelSize = getPixelSize(); - TPointD pa = getValue(m_pa); - TPointD pb = getValue(m_pb); - TPointD pc = getValue(m_pc); - TPointD pd = getValue(m_pd); + + // lines for moving all vertices + glPushName(idBase + Body); + setColorById(Body); + double pixelSize = getPixelSize(); + TPointD topLeft = getValue(m_TL); + TPointD topRight = getValue(m_TR); + TPointD bottomRight = getValue(m_BR); + TPointD bottomLeft = getValue(m_BL); glLineStipple(1, 0xCCCC); glEnable(GL_LINE_STIPPLE); glBegin(GL_LINE_STRIP); - tglVertex(pa); - tglVertex(pb); - tglVertex(pc); - tglVertex(pd); - tglVertex(pa); + tglVertex(topLeft); + tglVertex(topRight); + tglVertex(bottomRight); + tglVertex(bottomLeft); + tglVertex(topLeft); glEnd(); glDisable(GL_LINE_STIPPLE); - // glPopName(); + glPopName(); + + // corners + drawPoint(topLeft, TopLeft); + drawPoint(topRight, TopRight); + drawPoint(bottomRight, BottomRight); + drawPoint(bottomLeft, BottomLeft); + + // center of the edges + drawPoint((topLeft + topRight) * 0.5, TopEdge); + drawPoint((topRight + bottomRight) * 0.5, RightEdge); + drawPoint((bottomRight + bottomLeft) * 0.5, BottomEdge); + drawPoint((bottomLeft + topLeft) * 0.5, LeftEdge); } - void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {} - void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override {} - void leftButtonUp(const TPointD &pos, const TMouseEvent &) override {} + void leftButtonDown(const TPointD &pos, const TMouseEvent &) override; + void leftButtonDrag(const TPointD &pos, const TMouseEvent &) override; + void leftButtonUp(const TPointD &pos, const TMouseEvent &) override; }; +//--------------------------------------------------------------------------- + +void QuadFxGadget::leftButtonDown(const TPointD &pos, const TMouseEvent &) { + m_handle = (HANDLE)m_selected; + m_dragStartPos = pos; + m_startTL = getValue(m_TL); + m_startTR = getValue(m_TR); + m_startBR = getValue(m_BR); + m_startBL = getValue(m_BL); + m_pivot = (m_startTL + m_startTR + m_startBR + m_startBL) * 0.25; +} + +//--------------------------------------------------------------------------- + +void QuadFxGadget::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { + TPointD offset = pos - m_dragStartPos; + + auto scaleShape = [&](const TPointD &start, const TPointD &pivot) { + TPointD startVec = start - pivot; + TPointD endVec = start + offset - pivot; + TPointD scaleFac((startVec.x == 0.0) ? 1.0 : endVec.x / startVec.x, + (startVec.y == 0.0) ? 1.0 : endVec.y / startVec.y); + if (e.isShiftPressed()) { + if (std::abs(scaleFac.x) > std::abs(scaleFac.y)) + scaleFac.y = scaleFac.x; + else + scaleFac.x = scaleFac.y; + } + if (m_startTL != pivot) + setValue(m_TL, pivot + hadamard((m_startTL - pivot), scaleFac)); + if (m_startTR != pivot) + setValue(m_TR, pivot + hadamard((m_startTR - pivot), scaleFac)); + if (m_startBR != pivot) + setValue(m_BR, pivot + hadamard((m_startBR - pivot), scaleFac)); + if (m_startBL != pivot) + setValue(m_BL, pivot + hadamard((m_startBL - pivot), scaleFac)); + }; + + auto doCorner = [&](const TPointParamP point, const TPointD &start, + const TPointD &opposite) { + if (e.isCtrlPressed()) + setValue(point, start + offset); + else if (e.isAltPressed()) + scaleShape(start, m_pivot); + else + scaleShape(start, opposite); + }; + + auto doEdge = [&](const TPointParamP p1, const TPointParamP p2) { + if (e.isShiftPressed()) { + if (std::abs(offset.x) > std::abs(offset.y)) + offset.y = 0; + else + offset.x = 0; + } + if (m_TL == p1 || m_TL == p2) + setValue(m_TL, m_startTL + offset); + else if (e.isAltPressed()) + setValue(m_TL, m_startTL - offset); + if (m_TR == p1 || m_TR == p2) + setValue(m_TR, m_startTR + offset); + else if (e.isAltPressed()) + setValue(m_TR, m_startTR - offset); + if (m_BR == p1 || m_BR == p2) + setValue(m_BR, m_startBR + offset); + else if (e.isAltPressed()) + setValue(m_BR, m_startBR - offset); + if (m_BL == p1 || m_BL == p2) + setValue(m_BL, m_startBL + offset); + else if (e.isAltPressed()) + setValue(m_BL, m_startBL - offset); + }; + + auto pointRotate = [&](const TPointD pos, const double angle) { + TPointD p = pos - m_pivot; + return m_pivot + TPointD(p.x * std::cos(angle) - p.y * std::sin(angle), + p.x * std::sin(angle) + p.y * std::cos(angle)); + }; + + switch (m_handle) { + case Body: + if (e.isCtrlPressed()) { // rotate + TPointD startVec = m_dragStartPos - m_pivot; + TPointD currentVec = pos - m_pivot; + if (currentVec == TPointD()) return; + double angle = std::atan2(currentVec.y, currentVec.x) - + std::atan2(startVec.y, startVec.x); + if (e.isShiftPressed()) { + angle = std::round(angle / (M_PI / 2.0)) * (M_PI / 2.0); + } + setValue(m_TL, pointRotate(m_startTL, angle)); + setValue(m_TR, pointRotate(m_startTR, angle)); + setValue(m_BR, pointRotate(m_startBR, angle)); + setValue(m_BL, pointRotate(m_startBL, angle)); + } else { // translate + // move all shapes + if (e.isShiftPressed()) { + if (std::abs(offset.x) > std::abs(offset.y)) + offset.y = 0; + else + offset.x = 0; + } + setValue(m_TL, m_startTL + offset); + setValue(m_TR, m_startTR + offset); + setValue(m_BR, m_startBR + offset); + setValue(m_BL, m_startBL + offset); + } + break; + case TopLeft: + doCorner(m_TL, m_startTL, m_startBR); + break; + case TopRight: + doCorner(m_TR, m_startTR, m_startBL); + break; + case BottomRight: + doCorner(m_BR, m_startBR, m_startTL); + break; + case BottomLeft: + doCorner(m_BL, m_startBL, m_startTR); + break; + case TopEdge: + doEdge(m_TL, m_TR); + break; + case RightEdge: + doEdge(m_TR, m_BR); + break; + case BottomEdge: + doEdge(m_BR, m_BL); + break; + case LeftEdge: + doEdge(m_BL, m_TL); + break; + default: + break; + } +} + +//--------------------------------------------------------------------------- + +void QuadFxGadget::leftButtonUp(const TPointD &pos, const TMouseEvent &) { + m_handle = None; +} + //************************************************************************************* // FxGadgetController implementation //************************************************************************************* @@ -981,8 +1202,10 @@ void FxGadgetController::clearGadgets() { void FxGadgetController::assignId(FxGadget *gadget) { gadget->setId(m_nextId); - m_idTable[m_nextId] = gadget; - ++m_nextId; + for (int g = 0; g < gadget->getHandleCount(); g++) { + m_idTable[m_nextId] = gadget; + ++m_nextId; + } } //--------------------------------------------------------------------------- @@ -1009,9 +1232,10 @@ void FxGadgetController::selectById(unsigned int id) { it = m_idTable.find(id); FxGadget *selectedGadget = it != m_idTable.end() ? it->second : 0; if (selectedGadget != m_selectedGadget) { - if (m_selectedGadget) m_selectedGadget->select(false); + if (m_selectedGadget) m_selectedGadget->select(-1); m_selectedGadget = selectedGadget; - if (m_selectedGadget) m_selectedGadget->select(true); + if (m_selectedGadget) + m_selectedGadget->select(id - m_selectedGadget->getId()); } } @@ -1144,7 +1368,7 @@ void FxGadgetController::onFxSwitched() { // before, the levels were considered as nonZeraryFx and the edit tool // gadget was not displayed! Vinz { - if (zfx) fx = zfx->getZeraryFx(); + if (zfx) fx = zfx->getZeraryFx(); m_editingNonZeraryFx = false; } diff --git a/toonz/sources/tnztools/edittoolgadgets.h b/toonz/sources/tnztools/edittoolgadgets.h index 27e6e12..a26141f 100644 --- a/toonz/sources/tnztools/edittoolgadgets.h +++ b/toonz/sources/tnztools/edittoolgadgets.h @@ -32,7 +32,6 @@ class TParamUIConcept; class FxGadget : public TParamObserver { GLuint m_id; - bool m_selected; std::vector m_params; double m_pixelSize; @@ -42,11 +41,14 @@ class FxGadget : public TParamObserver { protected: FxGadgetController *m_controller; + int m_handleCount = 1; + // -1 : not selected, 0~ : handle id + int m_selected; public: static GLdouble m_selectedColor[3]; // rgb - FxGadget(FxGadgetController *controller); + FxGadget(FxGadgetController *controller, int handleCount = 1); virtual ~FxGadget(); void setLabel(std::string label) { m_label = label; } @@ -64,8 +66,11 @@ public: void setId(GLuint id) { m_id = id; } GLuint getId() const { return m_id; } - void select(bool selected) { m_selected = selected; } - bool isSelected() const { return m_selected; } + int getHandleCount() { return m_handleCount; } + + void select(int selected) { m_selected = selected; } + bool isSelected() const { return m_selected >= 0; } + bool isSelected(int id) const { return m_selected == id; } void setPixelSize(); // uses tglGetPixelSize2() void setPixelSize(double pixelSize) { m_pixelSize = pixelSize; } @@ -108,7 +113,7 @@ public: //----------------------------------------------------------------------------- -} // EditToolGadgets namespace +} // namespace EditToolGadgets class FxGadgetController final : public QObject { Q_OBJECT diff --git a/toonz/sources/tnztools/fingertool.cpp b/toonz/sources/tnztools/fingertool.cpp index f3871d4..f7b501f 100644 --- a/toonz/sources/tnztools/fingertool.cpp +++ b/toonz/sources/tnztools/fingertool.cpp @@ -1,6 +1,6 @@ //------------------------------------------------------ /*! Finger Tool : 線のノイズを埋めるツール -*/ + */ #include "tstroke.h" #include "tools/toolutils.h" #include "tools/tool.h" @@ -313,12 +313,14 @@ FingerTool::FingerTool() , m_selecting(false) , m_tileSaver(0) , m_cursor(ToolCursor::EraserCursor) - , m_toolSize("Size:", 1, 100, 10, false) + , m_toolSize("Size:", 1, 1000, 10, false) , m_invert("Invert", false) , m_firstTime(true) , m_workingFrameId(TFrameId()) { bind(TTool::ToonzImage); + m_toolSize.setNonLinearSlider(); + m_prop.bind(m_toolSize); m_prop.bind(m_invert); @@ -504,7 +506,7 @@ void FingerTool::onDeactivate() { //----------------------------------------------------------------------------- /*! * ドラッグ中にツールが切り替わった場合に備え、onDeactivateにもMouseReleaseと同じ処理を行う -*/ + */ void FingerTool::finishBrush() { if (TToonzImageP ti = (TToonzImageP)getImage(true)) { if (m_rasterTrack) { @@ -576,9 +578,8 @@ void FingerTool::pick(const TPointD &pos) { /*--- * pickLineモードのとき、PurePaintの部分をクリックしてもカレントStyleを変えない * ---*/ - if (ti && - picker.pickTone(TScale(1.0 / subsampling) * pos + - TPointD(-0.5, -0.5)) == 255) + if (ti && picker.pickTone(TScale(1.0 / subsampling) * pos + + TPointD(-0.5, -0.5)) == 255) return; } diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp index 95a4e57..765cbbd 100644 --- a/toonz/sources/tnztools/fullcolorbrushtool.cpp +++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp @@ -113,7 +113,7 @@ public: FullColorBrushTool::FullColorBrushTool(std::string name) : TTool(name) - , m_thickness("Size", 1, 100, 1, 5, false) + , m_thickness("Size", 1, 1000, 1, 5, false) , m_pressure("Pressure", true) , m_opacity("Opacity", 0, 100, 100, 100, true) , m_hardness("Hardness:", 0, 100, 100) @@ -133,6 +133,8 @@ FullColorBrushTool::FullColorBrushTool(std::string name) , m_firstTime(true) { bind(TTool::RasterImage | TTool::EmptyTarget); + m_thickness.setNonLinearSlider(); + m_prop.bind(m_thickness); m_prop.bind(m_hardness); m_prop.bind(m_opacity); @@ -302,7 +304,7 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, if (!viewer) return; TRasterImageP ri = (TRasterImageP)getImage(true); - if (!ri) ri = (TRasterImageP)touchImage(); + if (!ri) ri = (TRasterImageP)touchImage(); if (!ri) return; @@ -318,7 +320,13 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos, TPointD rasCenter = ras->getCenterD(); TPointD point(pos + rasCenter); - double pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + + double pressure; + if (getApplication()->getCurrentLevelStyle()->getTagId() == + 4001) // mypaint brush case + pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + else + pressure = m_enabledPressure ? e.m_pressure : 1.0; m_tileSet = new TTileSetFullColor(ras->getSize()); m_tileSaver = new TTileSaverFullColor(ras, m_tileSet); @@ -358,7 +366,12 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos, TRasterP ras = ri->getRaster(); TPointD rasCenter = ras->getCenterD(); TPointD point(pos + rasCenter); - double pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + double pressure; + if (getApplication()->getCurrentLevelStyle()->getTagId() == + 4001) // mypaint brush case + pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + else + pressure = m_enabledPressure ? e.m_pressure : 1.0; m_strokeSegmentRect.empty(); m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); @@ -389,7 +402,12 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos, TRasterP ras = ri->getRaster(); TPointD rasCenter = ras->getCenterD(); TPointD point(pos + rasCenter); - double pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + double pressure; + if (getApplication()->getCurrentLevelStyle()->getTagId() == + 4001) // mypaint brush case + pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5; + else + pressure = m_enabledPressure ? e.m_pressure : 1.0; m_strokeSegmentRect.empty(); m_toonz_brush->strokeTo(point, pressure, restartBrushTimer()); @@ -747,13 +765,7 @@ void FullColorBrushTool::updateCurrentStyle() { m_minCursorThick = std::max(m_thickness.getValue().first, 1); m_maxCursorThick = std::max(m_thickness.getValue().second, m_minCursorThick); - if (!m_enabledPressure) { - double minRadiusLog = log(0.5 * m_minCursorThick); - double maxRadiusLog = log(0.5 * m_maxCursorThick); - double avgRadiusLog = 0.5 * (minRadiusLog + maxRadiusLog); - double avgRadius = exp(avgRadiusLog); - m_minCursorThick = m_maxCursorThick = (int)round(2.0 * avgRadius); - } + if (!m_enabledPressure) m_minCursorThick = m_maxCursorThick; } // if this function is called from onEnter(), the clipping rect will not be diff --git a/toonz/sources/tnztools/fullcolorerasertool.cpp b/toonz/sources/tnztools/fullcolorerasertool.cpp index 5f523d6..2b66c18 100644 --- a/toonz/sources/tnztools/fullcolorerasertool.cpp +++ b/toonz/sources/tnztools/fullcolorerasertool.cpp @@ -368,7 +368,7 @@ private: FullColorEraserTool::FullColorEraserTool(std::string name) : TTool(name) - , m_size("Size:", 1, 100, 5, false) + , m_size("Size:", 1, 1000, 5, false) , m_opacity("Opacity:", 0, 100, 100) , m_hardness("Hardness:", 0, 100, 100) , m_eraseType("Type:") @@ -385,6 +385,8 @@ FullColorEraserTool::FullColorEraserTool(std::string name) , m_isXsheetCell(false) { bind(TTool::RasterImage); + m_size.setNonLinearSlider(); + m_prop.bind(m_size); m_prop.bind(m_hardness); m_prop.bind(m_opacity); @@ -987,7 +989,7 @@ void FullColorEraserTool::update(const TRasterImageP &ri, TRectD selArea, tileSet->add(raster, TRasterImageUtils::convertWorldToRaster(selArea, ri)); TUndo *undo; - undo = new RectFullColorUndo(tileSet, selArea, TStroke(), + undo = new RectFullColorUndo(tileSet, selArea, TStroke(), m_eraseType.getValue(), level.getPointer(), m_invertOption.getValue(), frameId); TRect rect = TRasterImageUtils::eraseRect(ri, selArea); diff --git a/toonz/sources/tnztools/magnettool.cpp b/toonz/sources/tnztools/magnettool.cpp index 1343638..3808f21 100644 --- a/toonz/sources/tnztools/magnettool.cpp +++ b/toonz/sources/tnztools/magnettool.cpp @@ -118,7 +118,6 @@ class MagnetTool final : public TTool { DoublePair m_extremes; int m_cursorId; - double m_pointSize; TUndo *m_undo; typedef struct { @@ -142,11 +141,13 @@ public: MagnetTool() : TTool("T_Magnet") , m_active(false) - , m_pointSize(-1) , m_oldStrokesArray() - , m_toolSize("Size:", 0, 100, 20) // W_ToolOptions_MagnetTool + , m_toolSize("Size:", 10, 500, 20) // W_ToolOptions_MagnetTool { bind(TTool::Vectors); + + m_toolSize.setNonLinearSlider(); + m_prop.bind(m_toolSize); } @@ -159,12 +160,8 @@ public: m_cursorId = ToolCursor::MagnetCursor; else m_cursorId = ToolCursor::CURSOR_NO; - - updatePointSize(); } - void onLeave() override { m_pointSize = -1; } - void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override { TPointD p(pos); @@ -190,6 +187,8 @@ public: m_hitStrokeCorners.clear(); m_strokeToModifyCorners.clear(); + double pointSize = m_toolSize.getValue(); + UINT i = 0; for (; i < vi->getStrokeCount(); ++i) { if (!vi->inCurrentGroup(i)) continue; @@ -198,11 +197,11 @@ public: ref = stroke; // calcola le intersezioni std::vector intersections; - intersect(*ref, p, m_pointSize, intersections); + intersect(*ref, p, pointSize, intersections); if (intersections.empty()) { if (increaseControlPoints(*ref, - TStrokePointDeformation(p, m_pointSize))) { + TStrokePointDeformation(p, pointSize))) { m_changedStrokes.push_back(i); m_strokeHit.push_back(ref); @@ -225,11 +224,11 @@ public: splitStroke(*sc.m_parent, intersections, sc.m_splitted); - selectStrokeToMove(sc.m_splitted, p, m_pointSize, sc.m_splittedToMove); + selectStrokeToMove(sc.m_splitted, p, pointSize, sc.m_splittedToMove); for (UINT ii = 0; ii < sc.m_splittedToMove.size(); ++ii) { TStroke *temp = sc.m_splittedToMove[ii]; bool test = increaseControlPoints( - *temp, TStrokePointDeformation(p, m_pointSize)); + *temp, TStrokePointDeformation(p, pointSize)); assert(test); std::vector *corners = new std::vector; @@ -245,7 +244,7 @@ public: } m_oldStrokesArray.resize(m_changedStrokes.size()); - for (i = 0; i < m_changedStrokes.size(); i++) + for (i = 0; i < m_changedStrokes.size(); i++) m_oldStrokesArray[i] = new TStroke(*(vi->getStroke(m_changedStrokes[i]))); if (!strokeUndo.empty()) { @@ -288,19 +287,21 @@ leftButtonUp(p); lefrightButtonDown(p); } */ + double pointSize = m_toolSize.getValue(); + UINT i, j; for (i = 0; i < m_strokeHit.size(); ++i) - modifyControlPoints(*m_strokeHit[i], - TStrokePointDeformation(offset, m_pointAtMouseDown, - m_pointSize * 0.7)); + modifyControlPoints( + *m_strokeHit[i], + TStrokePointDeformation(offset, m_pointAtMouseDown, pointSize * 0.7)); for (i = 0; i < m_strokeToModify.size(); ++i) for (j = 0; j < m_strokeToModify[i].m_splittedToMove.size(); ++j) { TStroke *temp = m_strokeToModify[i].m_splittedToMove[j]; modifyControlPoints(*temp, TStrokePointDeformation(offset, m_pointAtMouseDown, - m_pointSize * 0.7)); + pointSize * 0.7)); } m_pointAtMove = p; @@ -399,10 +400,10 @@ lefrightButtonDown(p); // glPushMatrix(); // tglMultMatrix(viewMatrix); - if (m_pointSize > 0) { - tglColor(TPixel32::Red); - tglDrawCircle(m_pointAtMove, m_pointSize); - } + double pointSize = m_toolSize.getValue(); + + tglColor(TPixel32::Red); + tglDrawCircle(m_pointAtMove, pointSize); if (!m_active) { // glPopMatrix(); @@ -439,31 +440,14 @@ lefrightButtonDown(p); int getCursorId() const override { return m_cursorId; } - bool onPropertyChanged(std::string propertyName) override - { - if(propertyName == m_toolSize.getName()) { - updatePointSize(); + bool onPropertyChanged(std::string propertyName) override { + if (propertyName == m_toolSize.getName()) { invalidate(); } return true; } -private: - /// Update point size based on property. - void updatePointSize() - { - double x = m_toolSize.getValue(); - - double minRange = 1; - double maxRange = 100; - - double minSize = 10; - double maxSize = 100; - - m_pointSize = - (x - minRange) / (maxRange - minRange) * (maxSize - minSize) + minSize; - } } magnetTool; // TTool *getMagnetTool() {return &magnetTool;} diff --git a/toonz/sources/tnztools/paintbrushtool.cpp b/toonz/sources/tnztools/paintbrushtool.cpp index d600870..c662fd4 100644 --- a/toonz/sources/tnztools/paintbrushtool.cpp +++ b/toonz/sources/tnztools/paintbrushtool.cpp @@ -318,11 +318,13 @@ PaintBrushTool::PaintBrushTool() , m_tileSaver(0) , m_cursor(ToolCursor::EraserCursor) // sostituire i nomi con quelli del current, tipo W_ToolOptions... - , m_toolSize("Size:", 1, 100, 10, false) // W_ToolOptions_BrushToolSize - , m_colorType("Mode:") // W_ToolOptions_InkOrPaint - , m_onlyEmptyAreas("Selective", false) // W_ToolOptions_Selective + , m_toolSize("Size:", 1, 1000, 10, false) // W_ToolOptions_BrushToolSize + , m_colorType("Mode:") // W_ToolOptions_InkOrPaint + , m_onlyEmptyAreas("Selective", false) // W_ToolOptions_Selective , m_firstTime(true) , m_workingFrameId(TFrameId()) { + m_toolSize.setNonLinearSlider(); + m_colorType.addValue(LINES); m_colorType.addValue(AREAS); m_colorType.addValue(ALL); diff --git a/toonz/sources/tnztools/pinchtool.cpp b/toonz/sources/tnztools/pinchtool.cpp index 004db42..b344672 100644 --- a/toonz/sources/tnztools/pinchtool.cpp +++ b/toonz/sources/tnztools/pinchtool.cpp @@ -81,6 +81,8 @@ PinchTool::PinchTool() , m_selector(500, 10, 1000) { bind(TTool::Vectors); + m_toolRange.setNonLinearSlider(); + m_prop.bind(m_toolCornerSize); m_prop.bind(m_autoOrManual); m_prop.bind(m_toolRange); @@ -138,7 +140,7 @@ void PinchTool::updateInterfaceStatus(const TMouseEvent &event) { m_status.key_event_ = ContextStatus::NONE; // mutual exclusive - if (event.isCtrlPressed()) m_status.key_event_ = ContextStatus::CTRL; + if (event.isCtrlPressed()) m_status.key_event_ = ContextStatus::CTRL; if (event.isShiftPressed()) m_status.key_event_ = ContextStatus::SHIFT; // TODO: **DEVE** essere fatto dentro la costruzione di TMouseEvent @@ -357,7 +359,7 @@ void PinchTool::onEnter() { //----------------------------------------------------------------------------- void PinchTool::onLeave() { - if (!m_active) m_draw = false; + if (!m_active) m_draw = false; m_status.stroke2change_ = 0; // Abbiamo dovuto commentarlo perche' stranamente diff --git a/toonz/sources/tnztools/rastererasertool.cpp b/toonz/sources/tnztools/rastererasertool.cpp index 8b86cdc..95b9056 100644 --- a/toonz/sources/tnztools/rastererasertool.cpp +++ b/toonz/sources/tnztools/rastererasertool.cpp @@ -281,7 +281,7 @@ void eraseStroke(const TToonzImageP &ti, TStroke *stroke, if (!invert) area = rasterErasedArea.enlarge(2); else - area = ras->getBounds(); + area = ras->getBounds(); TTileSetCM32 *tileSet = new TTileSetCM32(ras->getSize()); tileSet->add(ras, area); TUndoManager::manager()->add(new RectRasterUndo( @@ -569,7 +569,7 @@ EraserTool inkPaintEraserTool("T_Eraser"); EraserTool::EraserTool(std::string name) : TTool(name) - , m_toolSize("Size:", 1, 100, 10, false) // W_ToolOptions_EraserToolSize + , m_toolSize("Size:", 1, 1000, 10, false) // W_ToolOptions_EraserToolSize , m_hardness("Hardness:", 0, 100, 100) , m_eraseType("Type:") // W_ToolOptions_Erasetype , m_colorType("Mode:") // W_ToolOptions_InkOrPaint @@ -592,6 +592,8 @@ EraserTool::EraserTool(std::string name) , m_isLeftButtonPressed(false) { bind(TTool::ToonzImage); + m_toolSize.setNonLinearSlider(); + m_prop.bind(m_toolSize); m_prop.bind(m_hardness); m_prop.bind(m_eraseType); @@ -887,8 +889,8 @@ void EraserTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { int currentStyle = 0; if (m_currentStyle.getValue()) currentStyle = TTool::getApplication()->getCurrentLevelStyleIndex(); - m_tileSet = new TTileSetCM32(raster->getSize()); - m_tileSaver = new TTileSaverCM32(raster, m_tileSet); + m_tileSet = new TTileSetCM32(raster->getSize()); + m_tileSaver = new TTileSaverCM32(raster, m_tileSet); TPointD halfThick(m_toolSize.getValue() * 0.5, m_toolSize.getValue() * 0.5); invalidateRect = TRectD(pos - halfThick, pos + halfThick); @@ -898,7 +900,7 @@ void EraserTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { m_colorTypeEraser = INK; } if (m_colorType.getValue() == AREAS) m_colorTypeEraser = PAINT; - if (m_colorType.getValue() == ALL) m_colorTypeEraser = INKNPAINT; + if (m_colorType.getValue() == ALL) m_colorTypeEraser = INKNPAINT; m_normalEraser = new RasterStrokeGenerator( raster, ERASE, m_colorTypeEraser, 0, intPos, m_currentStyle.getValue(), currentStyle, @@ -1617,7 +1619,7 @@ void EraserTool::doMultiEraser(const TImageP &img, double t, //-------------------------------------------------------------------------------------------------- /*!ドラッグ中にツールが切り替わった時、終了処理を行う -*/ + */ void EraserTool::onDeactivate() { if (!m_isLeftButtonPressed || !m_selecting) return; @@ -1657,10 +1659,11 @@ void EraserTool::storeUndoAndRefresh() { TUndoManager::manager()->add(new RasterBluredEraserUndo( m_tileSet, m_points, TTool::getApplication()->getCurrentLevelStyleIndex(), - m_currentStyle.getValue(), TTool::getApplication() - ->getCurrentLevel() - ->getLevel() - ->getSimpleLevel(), + m_currentStyle.getValue(), + TTool::getApplication() + ->getCurrentLevel() + ->getLevel() + ->getSimpleLevel(), m_workingFrameId.isEmptyFrame() ? getCurrentFid() : m_workingFrameId, m_toolSize.getValue(), m_hardness.getValue() * 0.01, m_colorType.getValue())); @@ -1686,7 +1689,7 @@ void EraserTool::storeUndoAndRefresh() { //-------------------------------------------------------------------------------------------------- /*! Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す -*/ + */ bool EraserTool::isPencilModeActive() { return m_eraseType.getValue() == NORMALERASE && m_pencil.getValue(); } diff --git a/toonz/sources/tnztools/selectiontool.cpp b/toonz/sources/tnztools/selectiontool.cpp index 0d98fe3..ef9ae18 100644 --- a/toonz/sources/tnztools/selectiontool.cpp +++ b/toonz/sources/tnztools/selectiontool.cpp @@ -1023,7 +1023,8 @@ void SelectionTool::updateAction(TPointD pos, const TMouseEvent &e) { } if (!isLevelType() && !isSelectedFramesType() && tdistance2(getCenter(), pos) < maxDist2) { - m_what = MOVE_CENTER; + m_what = MOVE_CENTER; + m_cursorId = ToolCursor::PointingHandCursor; return; } TPointD hpos = bbox.getP10() - TPointD(14 * pixelSize, 15 * pixelSize); @@ -1214,7 +1215,8 @@ void SelectionTool::drawRectSelection(const TImage *image) { void SelectionTool::drawCommandHandle(const TImage *image) { const TVectorImage *vi = dynamic_cast(image); - TPixel32 frameColor(127, 127, 127); + TPixel32 frameColor(210, 210, 210); + TPixel32 frameColor2(0, 0, 0); FourPoints rect = getBBox(); drawFourPoints(rect, frameColor, 0xffff, true); @@ -1224,13 +1226,37 @@ void SelectionTool::drawCommandHandle(const TImage *image) { if (m_dragTool) m_dragTool->draw(); double pixelSize = getPixelSize(); - if (!isLevelType() && !isSelectedFramesType()) - tglDrawCircle(getCenter(), pixelSize * 4); + if (!isLevelType() && !isSelectedFramesType()) { + TPointD c = getCenter() + TPointD(-pixelSize, +pixelSize); + + tglColor(frameColor); + tglDrawCircle(c, pixelSize * 5); + tglDrawSegment(c - TPointD(pixelSize * 15, 0), + c + TPointD(pixelSize * 15, 0)); + tglDrawSegment(c - TPointD(0, pixelSize * 15), + c + TPointD(0, pixelSize * 15)); + tglColor(frameColor2); + tglDrawCircle(getCenter(), pixelSize * 5); + tglDrawSegment(getCenter() - TPointD(pixelSize * 15, 0), + getCenter() + TPointD(pixelSize * 15, 0)); + tglDrawSegment(getCenter() - TPointD(0, pixelSize * 15), + getCenter() + TPointD(0, pixelSize * 15)); + } + + TPointD bl(rect.getP00().x - pixelSize, rect.getP00().y + pixelSize); + TPointD tl(rect.getP01().x - pixelSize, rect.getP01().y + pixelSize); + TPointD br(rect.getP10().x - pixelSize, rect.getP10().y + pixelSize); + TPointD tr(rect.getP11().x - pixelSize, rect.getP11().y + pixelSize); - drawSquare(rect.getP00(), pixelSize * 4, frameColor); - drawSquare(rect.getP01(), pixelSize * 4, frameColor); - drawSquare(rect.getP10(), pixelSize * 4, frameColor); - drawSquare(rect.getP11(), pixelSize * 4, frameColor); + drawSquare(bl, pixelSize * 4, frameColor); + drawSquare(tl, pixelSize * 4, frameColor); + drawSquare(br, pixelSize * 4, frameColor); + drawSquare(tr, pixelSize * 4, frameColor); + + drawSquare(rect.getP00(), pixelSize * 4, frameColor2); + drawSquare(rect.getP01(), pixelSize * 4, frameColor2); + drawSquare(rect.getP10(), pixelSize * 4, frameColor2); + drawSquare(rect.getP11(), pixelSize * 4, frameColor2); if (vi && !m_deformValues.m_isSelectionModified) { TPointD thickCommandPos = @@ -1238,10 +1264,15 @@ void SelectionTool::drawCommandHandle(const TImage *image) { drawRectWhitArrow(thickCommandPos, pixelSize); } - drawSquare(0.5 * (rect.getP10() + rect.getP11()), pixelSize * 4, frameColor); - drawSquare(0.5 * (rect.getP01() + rect.getP11()), pixelSize * 4, frameColor); - drawSquare(0.5 * (rect.getP10() + rect.getP00()), pixelSize * 4, frameColor); - drawSquare(0.5 * (rect.getP01() + rect.getP00()), pixelSize * 4, frameColor); + drawSquare(0.5 * (br + tr), pixelSize * 4, frameColor); + drawSquare(0.5 * (tl + tr), pixelSize * 4, frameColor); + drawSquare(0.5 * (br + bl), pixelSize * 4, frameColor); + drawSquare(0.5 * (tl + bl), pixelSize * 4, frameColor); + + drawSquare(0.5 * (rect.getP10() + rect.getP11()), pixelSize * 4, frameColor2); + drawSquare(0.5 * (rect.getP01() + rect.getP11()), pixelSize * 4, frameColor2); + drawSquare(0.5 * (rect.getP10() + rect.getP00()), pixelSize * 4, frameColor2); + drawSquare(0.5 * (rect.getP01() + rect.getP00()), pixelSize * 4, frameColor2); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/tnztools/strokeselection.cpp b/toonz/sources/tnztools/strokeselection.cpp index 22ac15c..6a80c28 100644 --- a/toonz/sources/tnztools/strokeselection.cpp +++ b/toonz/sources/tnztools/strokeselection.cpp @@ -22,6 +22,7 @@ #include "toonz/tobjecthandle.h" #include "toonz/txshlevelhandle.h" #include "toonz/tscenehandle.h" +#include "toonz/txsheethandle.h" #include "toonz/tcenterlinevectorizer.h" #include "toonz/stage.h" @@ -196,22 +197,18 @@ public: // PasteStrokesUndo //----------------------------------------------------------------------------- -class PasteStrokesUndo final : public TUndo { - TXshSimpleLevelP m_level; - TFrameId m_frameId; +class PasteStrokesUndo final : public ToolUtils::TToolUndo { std::set m_indexes; - TPaletteP m_oldPalette; QMimeData *m_oldData; TSceneHandle *m_sceneHandle; public: PasteStrokesUndo(TXshSimpleLevel *level, const TFrameId &frameId, std::set &indexes, TPaletteP oldPalette, - TSceneHandle *sceneHandle) - : m_level(level) - , m_frameId(frameId) + TSceneHandle *sceneHandle, bool createdFrame, + bool createdLevel) + : TToolUndo(level, frameId, createdFrame, createdLevel, oldPalette) , m_indexes(indexes) - , m_oldPalette(oldPalette) , m_sceneHandle(sceneHandle) { QClipboard *clipboard = QApplication::clipboard(); m_oldData = cloneData(clipboard->mimeData()); @@ -230,9 +227,16 @@ public: std::set indexes = m_indexes; deleteStrokesWithoutUndo(image, indexes); + + removeLevelAndFrameIfNeeded(); + + TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged(); + notifyImageChanged(); } void redo() const override { + insertLevelAndFrameIfNeeded(); + TVectorImageP image = m_level->getFrame(m_frameId, true); std::set indexes = m_indexes; @@ -245,6 +249,9 @@ public: TTool::getApplication()->getCurrentTool()->getTool()->notifyImageChanged(); clipboard->setMimeData(data, QClipboard::Clipboard); + + TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged(); + notifyImageChanged(); } int getSize() const override { return sizeof(*this); } @@ -566,7 +573,8 @@ void StrokeSelection::paste() { TXshSimpleLevel *level = TTool::getApplication()->getCurrentLevel()->getSimpleLevel(); TUndoManager::manager()->add(new PasteStrokesUndo( - level, tool->getCurrentFid(), m_indexes, oldPalette, m_sceneHandle)); + level, tool->getCurrentFid(), m_indexes, oldPalette, m_sceneHandle, + tool->m_isFrameCreated, tool->m_isLevelCreated)); m_updateSelectionBBox = isPaste; } tool->notifyImageChanged(); diff --git a/toonz/sources/tnztools/tnztools.qrc b/toonz/sources/tnztools/tnztools.qrc index 98c61bc..a95ee1e 100644 --- a/toonz/sources/tnztools/tnztools.qrc +++ b/toonz/sources/tnztools/tnztools.qrc @@ -47,6 +47,7 @@ Resources/picker_style_organize.png Resources/picker_rgb.png Resources/picker_rgb_white.png + Resources/pointing_hand.png Resources/karasu.png Resources/ruler_modify.png Resources/ruler_new.png diff --git a/toonz/sources/tnztools/tooloptionscontrols.cpp b/toonz/sources/tnztools/tooloptionscontrols.cpp index 24f64bb..3e9bb68 100644 --- a/toonz/sources/tnztools/tooloptionscontrols.cpp +++ b/toonz/sources/tnztools/tooloptionscontrols.cpp @@ -148,6 +148,7 @@ ToolOptionSlider::ToolOptionSlider(TTool *tool, TDoubleProperty *property, : DoubleField() , ToolOptionControl(tool, property->getName(), toolHandle) , m_property(property) { + setLinearSlider(property->isLinearSlider()); m_property->addListener(this); TDoubleProperty::Range range = property->getRange(); setRange(range.first, range.second); @@ -250,6 +251,7 @@ ToolOptionPairSlider::ToolOptionPairSlider(TTool *tool, : DoublePairField(0, property->isMaxRangeLimited()) , ToolOptionControl(tool, property->getName(), toolHandle) , m_property(property) { + setLinearSlider(property->isLinearSlider()); m_property->addListener(this); TDoublePairProperty::Value value = property->getValue(); TDoublePairProperty::Range range = property->getRange(); @@ -377,6 +379,7 @@ ToolOptionIntPairSlider::ToolOptionIntPairSlider(TTool *tool, : IntPairField(0, property->isMaxRangeLimited()) , ToolOptionControl(tool, property->getName(), toolHandle) , m_property(property) { + setLinearSlider(property->isLinearSlider()); setLeftText(leftName); setRightText(rightName); m_property->addListener(this); @@ -491,6 +494,7 @@ ToolOptionIntSlider::ToolOptionIntSlider(TTool *tool, TIntProperty *property, : IntField(0, property->isMaxRangeLimited()) , ToolOptionControl(tool, property->getName(), toolHandle) , m_property(property) { + setLinearSlider(property->isLinearSlider()); m_property->addListener(this); TIntProperty::Range range = property->getRange(); setRange(range.first, range.second); @@ -621,7 +625,7 @@ void ToolOptionCombo::loadEntries() { }"); } } - int tmpWidth = fontMetrics().width(items[i].UIName); + int tmpWidth = fontMetrics().width(items[i].UIName); if (tmpWidth > maxWidth) maxWidth = tmpWidth; } @@ -655,8 +659,8 @@ void ToolOptionCombo::onActivated(int index) { void ToolOptionCombo::doShowPopup() { if (Preferences::instance()->getDropdownShortcutsCycleOptions()) { - const TEnumProperty::Range &range = m_property->getRange(); - int theIndex = currentIndex() + 1; + const TEnumProperty::Range &range = m_property->getRange(); + int theIndex = currentIndex() + 1; if (theIndex >= (int)range.size()) theIndex = 0; doOnActivated(theIndex); } else { @@ -738,8 +742,8 @@ void ToolOptionFontCombo::onActivated(int index) { void ToolOptionFontCombo::doShowPopup() { if (!isInVisibleViewer(this)) return; if (Preferences::instance()->getDropdownShortcutsCycleOptions()) { - const TEnumProperty::Range &range = m_property->getRange(); - int theIndex = currentIndex() + 1; + const TEnumProperty::Range &range = m_property->getRange(); + int theIndex = currentIndex() + 1; if (theIndex >= (int)range.size()) theIndex = 0; onActivated(theIndex); setCurrentIndex(theIndex); @@ -1415,8 +1419,8 @@ void PegbarCenterField::onChange(TMeasuredValue *fld, bool addToUndo) { TStageObject *obj = xsh->getStageObject(objId); - double v = fld->getValue(TMeasuredValue::MainUnit); - TPointD center = obj->getCenter(frame); + double v = fld->getValue(TMeasuredValue::MainUnit); + TPointD center = obj->getCenter(frame); if (!m_firstMouseDrag) m_oldCenter = center; if (m_index == 0) center.x = v; @@ -1507,7 +1511,7 @@ PropertyMenuButton::PropertyMenuButton(QWidget *parent, TTool *tool, setIcon(icon); setToolTip(tooltip); - QMenu *menu = new QMenu(tooltip, this); + QMenu *menu = new QMenu(tooltip, this); if (!tooltip.isEmpty()) tooltip = tooltip + " "; QActionGroup *actiongroup = new QActionGroup(this); @@ -1593,13 +1597,13 @@ bool SelectionScaleField::applyChange(bool addToUndo) { return false; DragSelectionTool::DragTool *scaleTool = createNewScaleTool(m_tool, 0); double p = getValue(); - if (p == 0) p = 0.00001; - DragSelectionTool::FourPoints points = m_tool->getBBox(); - TPointD center = m_tool->getCenter(); - TPointD p0M = points.getPoint(7); - TPointD p1M = points.getPoint(5); - TPointD pM1 = points.getPoint(6); - TPointD pM0 = points.getPoint(4); + if (p == 0) p = 0.00001; + DragSelectionTool::FourPoints points = m_tool->getBBox(); + TPointD center = m_tool->getCenter(); + TPointD p0M = points.getPoint(7); + TPointD p1M = points.getPoint(5); + TPointD pM1 = points.getPoint(6); + TPointD pM0 = points.getPoint(4); int pointIndex; TPointD sign(1, 1); TPointD scaleFactor = m_tool->m_deformValues.m_scaleValue; diff --git a/toonz/sources/tnztools/toonzrasterbrushtool.cpp b/toonz/sources/tnztools/toonzrasterbrushtool.cpp index c051fe6..41be132 100644 --- a/toonz/sources/tnztools/toonzrasterbrushtool.cpp +++ b/toonz/sources/tnztools/toonzrasterbrushtool.cpp @@ -251,8 +251,9 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim, double estremo_int = 0; double t = -1; if (q != TPointD(0, 0)) { - t = 0.25 * (2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x - - q.y * p0.y + q.y * p2.y) / + t = 0.25 * + (2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x - + q.y * p0.y + q.y * p2.y) / (q.x * q.x + q.y * q.y); dp = -p0 + p2 + 2 * q - 4 * t * q; // First derivate of the curve @@ -286,7 +287,7 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim, if (estremo_sx >= estremo_dx) t_ext = 0; else - t_ext = 1; + t_ext = 1; double maxEstremi = std::max(estremo_dx, estremo_sx); if (maxEstremi > estremo_int) { t = t_ext; @@ -600,9 +601,9 @@ public: //========================================================================================================= double computeThickness(double pressure, const TDoublePairProperty &property) { - double t = pressure * pressure * pressure; - double thick0 = property.getValue().first; - double thick1 = property.getValue().second; + double t = pressure * pressure * pressure; + double thick0 = property.getValue().first; + double thick1 = property.getValue().second; if (thick1 < 0.0001) thick0 = thick1 = 0.0; return (thick0 + (thick1 - thick0) * t) * 0.5; } @@ -821,7 +822,7 @@ void SmoothStroke::generatePoints() { ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) : TTool(name) - , m_rasThickness("Size", 1, 100, 1, 5) + , m_rasThickness("Size", 1, 1000, 1, 5) , m_smooth("Smooth:", 0, 50, 0) , m_hardness("Hardness:", 0, 100, 100) , m_preset("Preset:") @@ -842,6 +843,8 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType) , m_notifier(0) { bind(targetType); + m_rasThickness.setNonLinearSlider(); + m_prop[0].bind(m_rasThickness); m_prop[0].bind(m_hardness); m_prop[0].bind(m_smooth); @@ -1244,7 +1247,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, : maxThick; /*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する - * ---*/ + * ---*/ if (m_pressure.getValue() && e.m_pressure == 1.0) thickness = m_rasThickness.getValue().first; @@ -1305,7 +1308,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos, TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset); } else if (m_hardness.getValue() == 100 || m_pencil.getValue()) { /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる - * --*/ + * --*/ if (!m_pencil.getValue()) thickness -= 1.0; TThickPoint thickPoint(centeredPos + convert(ras->getCenter()), @@ -1408,7 +1411,7 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos, } else if (m_rasterTrack && (m_hardness.getValue() == 100 || m_pencil.getValue())) { /*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる - * --*/ + * --*/ if (!m_pencil.getValue()) thickness -= 1.0; TThickPoint thickPoint(centeredPos + rasCenter, thickness); @@ -1518,7 +1521,7 @@ void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos, //--------------------------------------------------------------------------------------------------------------- /*! * ドラッグ中にツールが切り替わった場合に備え、onDeactivate時とMouseRelease時にと同じ終了処理を行う -*/ + */ void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos, double pressureVal) { TToonzImageP ti = TImageP(getImage(true)); @@ -2096,7 +2099,7 @@ void ToonzRasterBrushTool::loadLastBrush() { //------------------------------------------------------------------ /*! Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す -*/ + */ bool ToonzRasterBrushTool::isPencilModeActive() { return getTargetType() == TTool::ToonzImage && m_pencil.getValue(); } diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.cpp b/toonz/sources/tnztools/toonzvectorbrushtool.cpp index 0f7c9b8..9acdabb 100644 --- a/toonz/sources/tnztools/toonzvectorbrushtool.cpp +++ b/toonz/sources/tnztools/toonzvectorbrushtool.cpp @@ -273,8 +273,9 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim, double estremo_int = 0; double t = -1; if (q != TPointD(0, 0)) { - t = 0.25 * (2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x - - q.y * p0.y + q.y * p2.y) / + t = 0.25 * + (2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x - + q.y * p0.y + q.y * p2.y) / (q.x * q.x + q.y * q.y); dp = -p0 + p2 + 2 * q - 4 * t * q; // First derivate of the curve @@ -308,7 +309,7 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim, if (estremo_sx >= estremo_dx) t_ext = 0; else - t_ext = 1; + t_ext = 1; double maxEstremi = std::max(estremo_dx, estremo_sx); if (maxEstremi > estremo_int) { t = t_ext; @@ -454,9 +455,9 @@ void getAboveStyleIdSet(int styleId, TPaletteP palette, double computeThickness(double pressure, const TDoublePairProperty &property, bool isPath) { if (isPath) return 0.0; - double t = pressure * pressure * pressure; - double thick0 = property.getValue().first; - double thick1 = property.getValue().second; + double t = pressure * pressure * pressure; + double thick0 = property.getValue().first; + double thick1 = property.getValue().second; if (thick1 < 0.0001) thick0 = thick1 = 0.0; return (thick0 + (thick1 - thick0) * t) * 0.5; } @@ -471,7 +472,7 @@ double computeThickness(double pressure, const TDoublePairProperty &property, ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType) : TTool(name) - , m_thickness("Size", 0, 100, 0, 5) + , m_thickness("Size", 0, 1000, 0, 5) , m_accuracy("Accuracy:", 1, 100, 20) , m_smooth("Smooth:", 0, 50, 0) , m_preset("Preset:") @@ -496,6 +497,9 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType) , m_targetType(targetType) , m_workingFrameId(TFrameId()) { bind(targetType); + + m_thickness.setNonLinearSlider(); + m_prop[0].bind(m_thickness); m_prop[0].bind(m_accuracy); m_prop[0].bind(m_smooth); @@ -607,8 +611,8 @@ void ToonzVectorBrushTool::onActivate() { void ToonzVectorBrushTool::onDeactivate() { /*--- - * �h���b�O���Ƀc�[�����؂�ւ�����ꍇ�ɔ����AonDeactivate�ɂ�MouseRelease�Ɠ����������s�� - * ---*/ + * �h���b�O���Ƀc�[�����؂�ւ�����ꍇ�ɔ����AonDeactivate�ɂ�MouseRelease�Ɠ����������s�� + * ---*/ // End current stroke. if (m_active && m_enabled) { @@ -684,7 +688,7 @@ void ToonzVectorBrushTool::leftButtonDown(const TPointD &pos, /*--- �X�g���[�N�̍ŏ���Max�T�C�Y�̉~���`����Ă��܂��s���h�~���� ---*/ if (m_pressure.getValue() && e.m_pressure == 1.0) - thickness = m_thickness.getValue().first * 0.5; + thickness = m_thickness.getValue().first * 0.5; m_currThickness = thickness; m_smoothStroke.beginStroke(m_smooth.getValue()); @@ -1183,7 +1187,7 @@ void ToonzVectorBrushTool::checkStrokeSnapping(bool beforeMousePress, if (Preferences::instance()->getVectorSnappingTarget() == 1) return; TVectorImageP vi(getImage(false)); - bool checkSnap = m_snap.getValue(); + bool checkSnap = m_snap.getValue(); if (invertCheck) checkSnap = !checkSnap; if (vi && checkSnap) { m_dragDraw = true; @@ -1233,8 +1237,8 @@ void ToonzVectorBrushTool::checkStrokeSnapping(bool beforeMousePress, } } if (snapFound) { - m_lastSnapPoint = TPointD(point1.x, point1.y); - m_foundLastSnap = true; + m_lastSnapPoint = TPointD(point1.x, point1.y); + m_foundLastSnap = true; if (distance2 < 2.0) m_dragDraw = false; } } @@ -1251,7 +1255,7 @@ void ToonzVectorBrushTool::checkGuideSnapping(bool beforeMousePress, beforeMousePress ? foundSnap = m_foundFirstSnap : foundSnap = m_foundLastSnap; beforeMousePress ? snapPoint = m_firstSnapPoint : snapPoint = m_lastSnapPoint; - bool checkSnap = m_snap.getValue(); + bool checkSnap = m_snap.getValue(); if (invertCheck) checkSnap = !checkSnap; if (checkSnap) { @@ -1314,8 +1318,8 @@ void ToonzVectorBrushTool::checkGuideSnapping(bool beforeMousePress, snapPoint.x = hGuide; } beforeMousePress ? m_foundFirstSnap = true : m_foundLastSnap = true; - beforeMousePress ? m_firstSnapPoint = snapPoint : m_lastSnapPoint = - snapPoint; + beforeMousePress ? m_firstSnapPoint = snapPoint + : m_lastSnapPoint = snapPoint; } } } @@ -1638,7 +1642,7 @@ void ToonzVectorBrushTool::loadLastBrush() { //------------------------------------------------------------------ /*! Brush�APaintBrush�AEraserTool��PencilMode�̂Ƃ���True��Ԃ� -*/ + */ bool ToonzVectorBrushTool::isPencilModeActive() { return false; } //========================================================================================================== diff --git a/toonz/sources/tnztools/vectorerasertool.cpp b/toonz/sources/tnztools/vectorerasertool.cpp index 9ea979c..d215060 100644 --- a/toonz/sources/tnztools/vectorerasertool.cpp +++ b/toonz/sources/tnztools/vectorerasertool.cpp @@ -65,7 +65,7 @@ void mapToVector(const std::map &theMap, std::vector &theVect) { assert(theMap.size() == theVect.size()); std::map::const_iterator it = theMap.begin(); - UINT i = 0; + UINT i = 0; for (; it != theMap.end(); ++it) { theVect[i++] = it->first; } @@ -146,7 +146,7 @@ public: image->removeStrokes(newStrokeIndex, true, false); std::map::const_iterator it = m_originalStrokes.begin(); - UINT i = 0; + UINT i = 0; VIStroke *s; for (; it != m_originalStrokes.end(); ++it) { s = cloneVIStroke(it->second); @@ -200,7 +200,7 @@ public: image->removeStrokes(oldStrokeIndex, true, false); std::map::const_iterator it = m_newStrokes.begin(); - UINT i = 0; + UINT i = 0; VIStroke *s; for (; it != m_newStrokes.end(); ++it) { s = cloneVIStroke(it->second); @@ -357,11 +357,11 @@ private: EraserTool::EraserTool() : TTool("T_Eraser") - , m_eraseType("Type:") // "W_ToolOptions_Erasetype" - , m_toolSize("Size:", 1, 100, 10) // "W_ToolOptions_EraserToolSize" - , m_selective("Selective", false) // "W_ToolOptions_Selective" - , m_invertOption("Invert", false) // "W_ToolOptions_Invert" - , m_multi("Frame Range", false) // "W_ToolOptions_FrameRange" + , m_eraseType("Type:") // "W_ToolOptions_Erasetype" + , m_toolSize("Size:", 1, 1000, 10) // "W_ToolOptions_EraserToolSize" + , m_selective("Selective", false) // "W_ToolOptions_Selective" + , m_invertOption("Invert", false) // "W_ToolOptions_Invert" + , m_multi("Frame Range", false) // "W_ToolOptions_FrameRange" , m_pointSize(-1) , m_undo(0) , m_currCell(-1, -1) @@ -371,6 +371,8 @@ EraserTool::EraserTool() , m_firstTime(true) { bind(TTool::VectorImage); + m_toolSize.setNonLinearSlider(); + m_prop.bind(m_toolSize); m_prop.bind(m_eraseType); m_eraseType.addValue(NORMAL_ERASE); @@ -1380,7 +1382,7 @@ void EraserTool::multiEreserRegion(TStroke *stroke, const TMouseEvent &e) { //----------------------------------------------------------------------------- /*! When the tool is switched during dragging, Erase end processing is performed -*/ + */ void EraserTool::onDeactivate() { if (!m_active) return; diff --git a/toonz/sources/toonz/main.cpp b/toonz/sources/toonz/main.cpp index 8c2bbeb..3c9d6a6 100644 --- a/toonz/sources/toonz/main.cpp +++ b/toonz/sources/toonz/main.cpp @@ -82,6 +82,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + using namespace DVGui; #if defined LINETEST const char *applicationName = "Toonz LineTest"; @@ -229,7 +233,7 @@ project->setUseScenePath(TProject::Extras, false); // Imposto la rootDir per ImageCache /*-- TOONZCACHEROOTの設定 --*/ - TFilePath cacheDir = ToonzFolder::getCacheRootFolder(); + TFilePath cacheDir = ToonzFolder::getCacheRootFolder(); if (cacheDir.isEmpty()) cacheDir = TEnv::getStuffDir() + "cache"; TImageCache::instance()->setRootDir(cacheDir); } @@ -315,10 +319,10 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); #ifdef MACOSX - // This workaround is to avoid missing left button problem on Qt5.6.0. - // To invalidate m_rightButtonClicked in Qt/qnsview.mm, sending - // NSLeftButtonDown event before NSLeftMouseDragged event propagated to - // QApplication. See more details in ../mousedragfilter/mousedragfilter.mm. +// This workaround is to avoid missing left button problem on Qt5.6.0. +// To invalidate m_rightButtonClicked in Qt/qnsview.mm, sending +// NSLeftButtonDown event before NSLeftMouseDragged event propagated to +// QApplication. See more details in ../mousedragfilter/mousedragfilter.mm. #include "mousedragfilter.h" @@ -616,6 +620,11 @@ int main(int argc, char *argv[]) { /*-- Layoutファイル名をMainWindowのctorに渡す --*/ MainWindow w(argumentLayoutFileName); +#ifdef _WIN32 + // http://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows + QWindowsWindowFunctions::setHasBorderInFullScreen(w.windowHandle(), true); +#endif + splash.showMessage(offsetStr + "Loading style sheet ...", Qt::AlignCenter, Qt::white); a.processEvents(); diff --git a/toonz/sources/toonz/sceneviewerevents.cpp b/toonz/sources/toonz/sceneviewerevents.cpp index 853bb43..c29f7dc 100644 --- a/toonz/sources/toonz/sceneviewerevents.cpp +++ b/toonz/sources/toonz/sceneviewerevents.cpp @@ -809,17 +809,17 @@ void SceneViewer::onRelease(const TMouseEvent &event) { quit: m_mouseButton = Qt::NoButton; - // If m_tabletState is "Touched", we've been called by tabletPress event. - // Don't clear it out table state so the tablePress event will process - // correctly. - if (m_tabletState != Touched) m_tabletState = None; - m_mouseState = None; - m_tabletMove = false; - m_pressure = 0; // Leave m_tabletEvent as-is in order to check whether the onRelease is called // from tabletEvent or not in mouseReleaseEvent. if (m_tabletState == Released) // only clear if tabletRelease event m_tabletEvent = false; + // If m_tabletState is "Touched", we've been called by tabletPress event. + // Don't clear it out table state so the tablePress event will process + // correctly. + if (m_tabletState != Touched) m_tabletState = None; + m_mouseState = None; + m_tabletMove = false; + m_pressure = 0; } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzlib/tcenterlinetostrokes.cpp b/toonz/sources/toonzlib/tcenterlinetostrokes.cpp index 300b38c..91932ac 100644 --- a/toonz/sources/toonzlib/tcenterlinetostrokes.cpp +++ b/toonz/sources/toonzlib/tcenterlinetostrokes.cpp @@ -425,7 +425,7 @@ bool SequenceConverter::parametrize(unsigned int a, unsigned int b) { //========================================================================== //------------------------ -// CP construcion +// CP construction //------------------------ // NOTE: Check my thesis for variable meanings (int_ stands for 'integral'). diff --git a/toonz/sources/toonzlib/tcleanupper.cpp b/toonz/sources/toonzlib/tcleanupper.cpp index 15abeaf..d813cc1 100644 --- a/toonz/sources/toonzlib/tcleanupper.cpp +++ b/toonz/sources/toonzlib/tcleanupper.cpp @@ -194,7 +194,7 @@ public: //========================================================================= -//! Birghtness/Contrast color transform data +//! Brightness/Contrast color transform data #define MAX_N_PENCILS 8 @@ -207,7 +207,7 @@ TPixelRGBM32 Paper = TPixel32::White; //========================================================================= -//! Birghtness/Contrast color transform structure +//! Brightness/Contrast color transform structure class TransfFunction { USHORT TransfFun[(MAX_N_PENCILS + 1) << 8]; diff --git a/toonz/sources/toonzqt/docklayout.cpp b/toonz/sources/toonzqt/docklayout.cpp index b5d7c2a..a83ba30 100644 --- a/toonz/sources/toonzqt/docklayout.cpp +++ b/toonz/sources/toonzqt/docklayout.cpp @@ -824,7 +824,7 @@ void Region::removeItem(DockWidget *item) { //! Undocks \b item and updates geometry. -//!\b NOTE: Window flags are resetted to floating appearance (thus hiding the +//!\b NOTE: Window flags are reset to floating appearance (thus hiding the //! widget). Since the geometry //! reference changes a geometry() update may be needed - so item's show() is //! not forced here. You should diff --git a/toonz/sources/toonzqt/doublefield.cpp b/toonz/sources/toonzqt/doublefield.cpp index 756c7a4..ff9305c 100644 --- a/toonz/sources/toonzqt/doublefield.cpp +++ b/toonz/sources/toonzqt/doublefield.cpp @@ -112,11 +112,11 @@ DoubleValueField::DoubleValueField(QWidget *parent, bool ret = true; ret = ret && connect(m_lineEdit, SIGNAL(valueChanged()), SLOT(onLineEditValueChanged())); - ret = ret && connect(m_roller, SIGNAL(valueChanged(bool)), + ret = ret && connect(m_roller, SIGNAL(valueChanged(bool)), SLOT(onRollerValueChanged(bool))); - ret = ret && connect(m_slider, SIGNAL(valueChanged(int)), + ret = ret && connect(m_slider, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int))); - ret = ret && + ret = ret && connect(m_slider, SIGNAL(sliderReleased()), SLOT(onSliderReleased())); ret = ret && connect(m_lineEdit, SIGNAL(editingFinished()), this, SIGNAL(valueEditedByHand())); @@ -133,6 +133,50 @@ DoubleValueField::DoubleValueField(QWidget *parent, //----------------------------------------------------------------------------- +double DoubleValueField::pos2value(int x) const { + int dicimal = m_lineEdit->getDecimals(); + if (m_isLinearSlider) return (double)x * pow(0.1, dicimal); + + // nonlinear slider case + double rangeSize = (double)(m_slider->maximum() - m_slider->minimum()); + double posRatio = (double)(x - m_slider->minimum()) / rangeSize; + double t; + if (posRatio <= 0.5) + t = 0.04 * posRatio; + else if (posRatio <= 0.75) + t = -0.02 + 0.08 * posRatio; + else if (posRatio <= 0.9) + t = -0.26 + 0.4 * posRatio; + else + t = -8.0 + 9.0 * posRatio; + double sliderValue = round((double)m_slider->minimum() + rangeSize * t); + return sliderValue * pow(0.1, dicimal); +} + +//----------------------------------------------------------------------------- + +int DoubleValueField::value2pos(double v) const { + int dicimal = m_lineEdit->getDecimals(); + double sliderValue = round(v * pow(10., dicimal)); + if (m_isLinearSlider) return (int)sliderValue; + + // nonlinear slider case + double rangeSize = (double)(m_slider->maximum() - m_slider->minimum()); + double valueRatio = (sliderValue - (double)m_slider->minimum()) / rangeSize; + double t; + if (valueRatio <= 0.02) + t = valueRatio / 0.04; + else if (valueRatio <= 0.04) + t = (valueRatio + 0.02) / 0.08; + else if (valueRatio <= 0.1) + t = (valueRatio + 0.26) / 0.4; + else + t = (valueRatio + 8.0) / 9.0; + return m_slider->minimum() + (int)(t * rangeSize); +} + +//----------------------------------------------------------------------------- + void DoubleValueField::getRange(double &minValue, double &maxValue) { m_lineEdit->getRange(minValue, maxValue); } @@ -159,11 +203,7 @@ void DoubleValueField::setValue(double value) { if (m_lineEdit->getValue() == value) return; m_lineEdit->setValue(value); m_roller->setValue(value); - - int dicimal = m_lineEdit->getDecimals(); - int sliderValue = (int)round(value * pow(10., dicimal)); - - m_slider->setValue(sliderValue); + m_slider->setValue(value2pos(value)); // forzo il repaint... non sempre si aggiorna e l'update non sembra risolvere // il ptroblema!!! m_slider->repaint(); @@ -215,9 +255,8 @@ bool DoubleValueField::isRollerEnabled() { return m_roller->isEnabled(); } //----------------------------------------------------------------------------- -void DoubleValueField::onSliderChanged(int value) { - int dicimal = m_lineEdit->getDecimals(); - double val = double(value) * pow(0.1, dicimal); +void DoubleValueField::onSliderChanged(int sliderPos) { + double val = pos2value(sliderPos); // Controllo necessario per evitare che il segnale di cambiamento venga emesso // piu' volte. @@ -237,16 +276,15 @@ void DoubleValueField::onSliderChanged(int value) { //----------------------------------------------------------------------------- void DoubleValueField::onLineEditValueChanged() { - double value = m_lineEdit->getValue(); - int dicimal = m_lineEdit->getDecimals(); - int sliderValue = (int)round(value * pow(10., dicimal)); + double value = m_lineEdit->getValue(); + int dicimal = m_lineEdit->getDecimals(); // Control necessary to prevent the change signal from being emitted more than // once. - if ((m_slider->value() == sliderValue && m_slider->isVisible()) || + if ((pos2value(m_slider->value()) == value && m_slider->isVisible()) || (m_roller->getValue() == value && m_roller->isVisible())) return; - m_slider->setValue(sliderValue); + m_slider->setValue(value2pos(value)); m_roller->setValue(value); emit valueChanged(false); } @@ -256,17 +294,14 @@ void DoubleValueField::onLineEditValueChanged() { void DoubleValueField::onRollerValueChanged(bool isDragging) { double value = m_roller->getValue(); - int dicimal = m_lineEdit->getDecimals(); - double sliderValue = value * pow(10., dicimal); - - if (sliderValue == m_lineEdit->getValue()) { - assert(m_slider->value() == value || !m_slider->isVisible()); + if (value == m_lineEdit->getValue()) { + assert(pos2value(m_slider->value()) == value || !m_slider->isVisible()); // Se isDragging e' falso e' giusto che venga emessa la notifica di // cambiamento. if (!isDragging) emit valueChanged(isDragging); return; } - m_slider->setValue(sliderValue); + m_slider->setValue(value2pos(value)); m_lineEdit->setValue(value); // Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa diff --git a/toonz/sources/toonzqt/doublepairfield.cpp b/toonz/sources/toonzqt/doublepairfield.cpp index 89aaecf..c895fc8 100644 --- a/toonz/sources/toonzqt/doublepairfield.cpp +++ b/toonz/sources/toonzqt/doublepairfield.cpp @@ -68,7 +68,7 @@ DoubleValuePairField::DoubleValuePairField(QWidget *parent, //---- signal-slot connections bool ret = connect(m_leftLineEdit, SIGNAL(editingFinished()), SLOT(onLeftEditingFinished())); - ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()), + ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()), SLOT(onRightEditingFinished())); assert(ret); } @@ -76,16 +76,45 @@ DoubleValuePairField::DoubleValuePairField(QWidget *parent, //----------------------------------------------------------------------------- double DoubleValuePairField::pos2value(int x) const { - int xMin = m_leftMargin, xMax = width() - m_rightMargin; - return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin); + int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1; + if (m_isLinear) + return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin); + + // nonlinear slider case + double posRatio = (double)(x - xMin) / (double)(xMax - xMin); + double t; + if (posRatio <= 0.5) + t = 0.04 * posRatio; + else if (posRatio <= 0.75) + t = -0.02 + 0.08 * posRatio; + else if (posRatio <= 0.9) + t = -0.26 + 0.4 * posRatio; + else + t = -8.0 + 9.0 * posRatio; + return m_minValue + (m_maxValue - m_minValue) * t; } //----------------------------------------------------------------------------- int DoubleValuePairField::value2pos(double v) const { - int xMin = m_leftMargin, xMax = width() - m_rightMargin; - return xMin + - (int)(((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue)); + int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1; + if (m_isLinear) + return xMin + (int)(((xMax - xMin) * (v - m_minValue)) / + (m_maxValue - m_minValue)); + + // nonlinear slider case + double valueRatio = + (v - (double)m_minValue) / (double)(m_maxValue - m_minValue); + double t; + if (valueRatio <= 0.02) + t = valueRatio / 0.04; + else if (valueRatio <= 0.04) + t = (valueRatio + 0.02) / 0.08; + else if (valueRatio <= 0.1) + t = (valueRatio + 0.26) / 0.4; + else + t = (valueRatio + 8.0) / 9.0; + return xMin + (int)(t * (double)(xMax - xMin)); } //----------------------------------------------------------------------------- @@ -266,7 +295,7 @@ void DoubleValuePairField::mousePressEvent(QMouseEvent *event) { void DoubleValuePairField::mouseMoveEvent(QMouseEvent *event) { if (event->buttons()) { std::pair oldValues = m_values; - int x = event->pos().x() + m_grabOffset; + int x = event->pos().x() + m_grabOffset; setValue(pos2value(x)); if (oldValues != m_values) { emit valuesChanged(true); @@ -291,7 +320,7 @@ void DoubleValuePairField::onLeftEditingFinished() { if (!m_isMaxRangeLimited && value < m_minValue) value = m_minValue; else if (m_isMaxRangeLimited) - value = tcrop(value, m_minValue, m_maxValue); + value = tcrop(value, m_minValue, m_maxValue); m_values.first = value; if (m_values.first > m_values.second) { m_values.second = m_values.first; @@ -307,7 +336,7 @@ void DoubleValuePairField::onRightEditingFinished() { double value = m_rightLineEdit->getValue(); if (value == m_values.second) return; if (m_isMaxRangeLimited) value = tcrop(value, m_minValue, m_maxValue); - m_values.second = value; + m_values.second = value; if (m_values.second < m_values.first) { m_values.first = m_values.second; m_leftLineEdit->setValue(m_values.first); diff --git a/toonz/sources/toonzqt/intfield.cpp b/toonz/sources/toonzqt/intfield.cpp index 1bc4fb8..300d0ad 100644 --- a/toonz/sources/toonzqt/intfield.cpp +++ b/toonz/sources/toonzqt/intfield.cpp @@ -11,6 +11,10 @@ #include #include +namespace { +const int NonLinearSliderPrecision = 2; +} + using namespace DVGui; //============================================================================= @@ -250,7 +254,8 @@ IntField::IntField(QWidget *parent, bool isMaxRangeLimited, bool isRollerHide) , m_lineEdit(0) , m_slider(0) , m_roller(0) - , m_isMaxRangeLimited(isMaxRangeLimited) { + , m_isMaxRangeLimited(isMaxRangeLimited) + , m_isLinearSlider(true) { setObjectName("IntField"); QHBoxLayout *layout = new QHBoxLayout(this); layout->setMargin(0); @@ -279,7 +284,7 @@ IntField::IntField(QWidget *parent, bool isMaxRangeLimited, bool isRollerHide) m_slider = new QSlider(Qt::Horizontal, this); ret = ret && connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int))); - ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this, + ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this, SLOT(onSliderReleased())); ret = ret && connect(m_lineEdit, SIGNAL(editingFinished()), this, @@ -309,7 +314,11 @@ void IntField::setRange(int minValue, int maxValue) { m_lineEdit->setRange(minValue, m_isMaxRangeLimited ? maxValue : (std::numeric_limits::max)()); - m_slider->setRange(minValue, maxValue); + if (m_isLinearSlider) + m_slider->setRange(minValue, maxValue); + else + m_slider->setRange(minValue * pow(10., NonLinearSliderPrecision), + maxValue * pow(10., NonLinearSliderPrecision)); m_roller->setRange(minValue, maxValue); } @@ -318,7 +327,7 @@ void IntField::setRange(int minValue, int maxValue) { void IntField::setValue(int value) { if (m_lineEdit->getValue() == value) return; m_lineEdit->setValue(value); - m_slider->setSliderPosition(value); + m_slider->setSliderPosition(value2pos(value)); m_roller->setValue((double)value); } @@ -369,7 +378,50 @@ void IntField::setLineEditBackgroundColor(QColor color) { //----------------------------------------------------------------------------- -void IntField::onSliderChanged(int value) { +int IntField::pos2value(int x) const { + if (m_isLinearSlider) return x; + + // nonlinear slider case + double rangeSize = (double)(m_slider->maximum() - m_slider->minimum()); + double posRatio = (double)(x - m_slider->minimum()) / rangeSize; + double t; + if (posRatio <= 0.5) + t = 0.04 * posRatio; + else if (posRatio <= 0.75) + t = -0.02 + 0.08 * posRatio; + else if (posRatio <= 0.9) + t = -0.26 + 0.4 * posRatio; + else + t = -8.0 + 9.0 * posRatio; + double sliderVal = (double)m_slider->minimum() + rangeSize * t; + return (int)round(sliderVal * pow(0.1, NonLinearSliderPrecision)); +} + +//----------------------------------------------------------------------------- + +int IntField::value2pos(int v) const { + if (m_isLinearSlider) return v; + + // nonlinear slider case + double sliderVal = (double)v * pow(10., NonLinearSliderPrecision); + double rangeSize = (double)(m_slider->maximum() - m_slider->minimum()); + double valueRatio = (double)(sliderVal - m_slider->minimum()) / rangeSize; + double t; + if (valueRatio <= 0.02) + t = valueRatio / 0.04; + else if (valueRatio <= 0.04) + t = (valueRatio + 0.02) / 0.08; + else if (valueRatio <= 0.1) + t = (valueRatio + 0.26) / 0.4; + else + t = (valueRatio + 8.0) / 9.0; + return m_slider->minimum() + (int)(t * rangeSize); +} + +//----------------------------------------------------------------------------- + +void IntField::onSliderChanged(int sliderPos) { + int value = pos2value(sliderPos); // Controllo necessario per evitare che il segnale di cambiamento venga emesso // piu' volte. if (m_lineEdit->getValue() == value || @@ -390,10 +442,10 @@ void IntField::onEditingFinished() { double value = m_lineEdit->getValue(); // Controllo necessario per evitare che il segnale di cambiamento venga emesso // piu' volte. - if ((m_slider->value() == value && m_slider->isVisible()) || + if ((pos2value(m_slider->value()) == value && m_slider->isVisible()) || (int)m_roller->getValue() == value && m_roller->isVisible()) return; - m_slider->setValue(value); + m_slider->setValue(value2pos(value)); m_roller->setValue((double)value); emit valueChanged(false); } @@ -403,13 +455,13 @@ void IntField::onEditingFinished() { void IntField::onRollerValueChanged(bool isDragging) { int value = m_roller->getValue(); if (value == m_lineEdit->getValue()) { - assert(m_slider->value() == value || !m_slider->isVisible()); + assert(pos2value(m_slider->value()) == value || !m_slider->isVisible()); // Se isDragging e' falso e' giusto che venga emessa la notifica di // cambiamento. if (!isDragging) emit valueChanged(isDragging); return; } - m_slider->setValue(value); + m_slider->setValue(value2pos(value)); m_lineEdit->setValue(value); // Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa diff --git a/toonz/sources/toonzqt/intpairfield.cpp b/toonz/sources/toonzqt/intpairfield.cpp index 0c1dd50..3db0a97 100644 --- a/toonz/sources/toonzqt/intpairfield.cpp +++ b/toonz/sources/toonzqt/intpairfield.cpp @@ -33,7 +33,8 @@ IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited) , m_grabIndex(-1) , m_leftMargin(52) , m_rightMargin(52) - , m_isMaxRangeLimited(isMaxRangeLimited) { + , m_isMaxRangeLimited(isMaxRangeLimited) + , m_isLinear(true) { setObjectName("IntPairField"); setFixedHeight(WidgetHeight); @@ -63,7 +64,7 @@ IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited) //---signal-slot connections bool ret = connect(m_leftLineEdit, SIGNAL(editingFinished()), SLOT(onLeftEditingFinished())); - ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()), + ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()), SLOT(onRightEditingFinished())); assert(ret); @@ -71,17 +72,46 @@ IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited) //----------------------------------------------------------------------------- -double IntPairField::pos2value(int x) const { +int IntPairField::pos2value(int x) const { int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1; - return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin); + if (m_isLinear) + return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin); + + // nonlinear slider case + double posRatio = (double)(x - xMin) / (double)(xMax - xMin); + double t; + if (posRatio <= 0.5) + t = 0.04 * posRatio; + else if (posRatio <= 0.75) + t = -0.02 + 0.08 * posRatio; + else if (posRatio <= 0.9) + t = -0.26 + 0.4 * posRatio; + else + t = -8.0 + 9.0 * posRatio; + return m_minValue + (int)((double)(m_maxValue - m_minValue) * t); } //----------------------------------------------------------------------------- -int IntPairField::value2pos(double v) const { +int IntPairField::value2pos(int v) const { int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1; - return xMin + - (int)(((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue)); + if (m_isLinear) + return xMin + + ((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue); + + // nonlinear slider case + double valueRatio = + (double)(v - m_minValue) / (double)(m_maxValue - m_minValue); + double t; + if (valueRatio <= 0.02) + t = valueRatio / 0.04; + else if (valueRatio <= 0.04) + t = (valueRatio + 0.02) / 0.08; + else if (valueRatio <= 0.1) + t = (valueRatio + 0.26) / 0.4; + else + t = (valueRatio + 8.0) / 9.0; + return xMin + (int)(t * (double)(xMax - xMin)); } //----------------------------------------------------------------------------- @@ -258,7 +288,7 @@ void IntPairField::mousePressEvent(QMouseEvent *event) { void IntPairField::mouseMoveEvent(QMouseEvent *event) { if (event->buttons()) { std::pair oldValues = m_values; - int x = event->pos().x() + m_grabOffset; + int x = event->pos().x() + m_grabOffset; setValue(pos2value(x)); if (oldValues == m_values) return; @@ -283,7 +313,7 @@ void IntPairField::onLeftEditingFinished() { if (!m_isMaxRangeLimited && value < m_minValue) value = m_minValue; else if (m_isMaxRangeLimited) - value = tcrop(value, m_minValue, m_maxValue); + value = tcrop(value, m_minValue, m_maxValue); m_values.first = value; if (m_values.first > m_values.second) { m_values.second = m_values.first; @@ -299,7 +329,7 @@ void IntPairField::onRightEditingFinished() { int value = m_rightLineEdit->getValue(); if (value == m_values.second) return; if (m_isMaxRangeLimited) value = tcrop(value, m_minValue, m_maxValue); - m_values.second = value; + m_values.second = value; if (m_values.second < m_values.first) { m_values.first = m_values.second; m_leftLineEdit->setValue(m_values.first);