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);