1 
2 
3 #include "toonzqt/doublepairfield.h"
4 #include "toonzqt/dvdialog.h"
5 
6 #include "tcommon.h"
7 
8 #include <cmath>
9 
10 #include <QLabel>
11 #include <QPainter>
12 #include <QMouseEvent>
13 #include <QSlider>
14 #include <QHBoxLayout>
15 
16 using namespace DVGui;
17 
18 #ifdef MACOSX
19 #define MARGIN_OFFSET 7
20 #else
21 #define MARGIN_OFFSET 2
22 #endif
23 
24 //=============================================================================
25 // DoubleValuePairField
26 //-----------------------------------------------------------------------------
27 
DoubleValuePairField(QWidget * parent,bool isMaxRangeLimited,DoubleValueLineEdit * leftLineEdit,DoubleValueLineEdit * rightLineEdit)28 DoubleValuePairField::DoubleValuePairField(QWidget *parent,
29                                            bool isMaxRangeLimited,
30                                            DoubleValueLineEdit *leftLineEdit,
31                                            DoubleValueLineEdit *rightLineEdit)
32     : QWidget(parent)
33     , m_values(0, 0)
34     , m_minValue(0)
35     , m_maxValue(100)
36     , m_grabOffset(0)
37     , m_grabIndex(-1)
38     , m_leftMargin(72)
39     , m_rightMargin(72)
40     , m_isMaxRangeLimited(isMaxRangeLimited)
41     , m_leftLineEdit(leftLineEdit)
42     , m_rightLineEdit(rightLineEdit)
43     , m_isLinear(true) {
44   assert(m_leftLineEdit);
45   assert(m_rightLineEdit);
46   setObjectName("DoublePairField");
47   setFixedHeight(WidgetHeight);
48 
49   m_leftLabel  = new QLabel("", this);
50   m_rightLabel = new QLabel("", this);
51 
52   m_leftLineEdit->setFixedWidth(60);
53   m_rightLineEdit->setFixedWidth(60);
54 
55   //---- layout
56   QHBoxLayout *m_mainLayout = new QHBoxLayout;
57   m_mainLayout->setMargin(0);
58   m_mainLayout->setSpacing(3);
59   {
60     m_mainLayout->addWidget(m_leftLabel, 1);
61     m_mainLayout->addWidget(m_leftLineEdit, 1, Qt::AlignLeft);
62     m_mainLayout->addSpacing(35);
63     m_mainLayout->addStretch(100);
64     m_mainLayout->addWidget(m_rightLabel, 1);
65     m_mainLayout->addWidget(m_rightLineEdit, 1, Qt::AlignRight);
66   }
67   setLayout(m_mainLayout);
68 
69   //---- signal-slot connections
70   bool ret = connect(m_leftLineEdit, SIGNAL(editingFinished()),
71                      SLOT(onLeftEditingFinished()));
72   ret      = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()),
73                        SLOT(onRightEditingFinished()));
74   assert(ret);
75 }
76 
77 //-----------------------------------------------------------------------------
78 
pos2value(int x) const79 double DoubleValuePairField::pos2value(int x) const {
80   int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
81   if (m_isLinear)
82     return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin);
83 
84   // nonlinear slider case
85   double posRatio = (double)(x - xMin) / (double)(xMax - xMin);
86   double t;
87   if (posRatio <= 0.5)
88     t = 0.04 * posRatio;
89   else if (posRatio <= 0.75)
90     t = -0.02 + 0.08 * posRatio;
91   else if (posRatio <= 0.9)
92     t = -0.26 + 0.4 * posRatio;
93   else
94     t = -8.0 + 9.0 * posRatio;
95   return m_minValue + (m_maxValue - m_minValue) * t;
96 }
97 
98 //-----------------------------------------------------------------------------
99 
value2pos(double v) const100 int DoubleValuePairField::value2pos(double v) const {
101   int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
102   if (m_isLinear)
103     return xMin + (int)(((xMax - xMin) * (v - m_minValue)) /
104                         (m_maxValue - m_minValue));
105 
106   // nonlinear slider case
107   double valueRatio =
108       (v - (double)m_minValue) / (double)(m_maxValue - m_minValue);
109   double t;
110   if (valueRatio <= 0.02)
111     t = valueRatio / 0.04;
112   else if (valueRatio <= 0.04)
113     t = (valueRatio + 0.02) / 0.08;
114   else if (valueRatio <= 0.1)
115     t = (valueRatio + 0.26) / 0.4;
116   else
117     t = (valueRatio + 8.0) / 9.0;
118   return xMin + (int)(t * (double)(xMax - xMin));
119 }
120 
121 //-----------------------------------------------------------------------------
122 
paintEvent(QPaintEvent *)123 void DoubleValuePairField::paintEvent(QPaintEvent *) {
124   QPainter p(this);
125   p.setBrush(Qt::NoBrush);
126 
127   int x0 = value2pos(m_minValue);
128   int x1 = value2pos(m_maxValue);
129   int y  = height() / 2;
130 
131   p.setPen(QPen(getDarkLineColor(), 4));
132   p.drawLine(x0 - 1, y, x1, y);
133 
134   p.setPen(Qt::black);
135 
136   int y1 = height() - 1;
137   int x;
138   x                = value2pos(m_values.first);
139   QRect sliderRect = QRect(x0, -5, x1 - x0 + 1, 10);
140 
141   if (sliderRect.contains(QPoint(x, 0)))
142     p.drawPixmap(x - m_handleLeftPixmap.width() + 1, 2, m_handleLeftPixmap);
143   else
144     p.drawPixmap(sliderRect.right() - m_handleLeftPixmap.width() + 1, 2,
145                  m_handleLeftGrayPixmap);
146 
147   x = value2pos(m_values.second);
148 
149   if (sliderRect.contains(QPoint(x, 0)))
150     p.drawPixmap(x, 2, m_handleRightPixmap);
151   else
152     p.drawPixmap(sliderRect.right(), 2, m_handleRightGrayPixmap);
153 }
154 
155 //-----------------------------------------------------------------------------
156 
setLeftText(const QString & text)157 void DoubleValuePairField::setLeftText(const QString &text) {
158   QString oldText = m_leftLabel->text();
159 
160   int oldLabelSize = fontMetrics().width(oldText);
161   int newLabelSize = fontMetrics().width(text);
162   int labelSize    = newLabelSize - oldLabelSize;
163   m_leftMargin += labelSize + MARGIN_OFFSET;
164 
165   m_leftLabel->setText(text);
166   update();
167 }
168 
169 //-----------------------------------------------------------------------------
170 
setRightText(const QString & text)171 void DoubleValuePairField::setRightText(const QString &text) {
172   QString oldText = m_rightLabel->text();
173 
174   int oldLabelSize = fontMetrics().width(oldText);
175   int newLabelSize = fontMetrics().width(text);
176   int labelSize    = newLabelSize - oldLabelSize;
177   m_rightMargin += labelSize + MARGIN_OFFSET;
178 
179   m_rightLabel->setText(text);
180   update();
181 }
182 
183 //-----------------------------------------------------------------------------
184 
setLabelsEnabled(bool enable)185 void DoubleValuePairField::setLabelsEnabled(bool enable) {
186   if (!enable) {
187     m_rightLabel->hide();
188     m_leftLabel->hide();
189   } else {
190     m_rightLabel->show();
191     m_leftLabel->show();
192   }
193 }
194 
195 //-----------------------------------------------------------------------------
196 
setValue(double value)197 void DoubleValuePairField::setValue(double value) {
198   int decimals = std::min(m_leftLineEdit->getDecimals(), 4);
199   value = tround(value * std::pow(10, decimals)) * std::pow(0.1, decimals);
200   value = tcrop(value, m_minValue, m_maxValue);
201   if (m_grabIndex == 0)  // Left grab
202   {
203     m_values.first = value;
204     m_leftLineEdit->setValue(m_values.first);
205 
206     if (value > m_values.second) {
207       m_values.second = value;
208       m_rightLineEdit->setValue(m_values.second);
209     }
210   } else  // Right grab
211   {
212     m_values.second = value;
213     m_rightLineEdit->setValue(m_values.second);
214 
215     if (value < m_values.first) {
216       m_values.first = value;
217       m_leftLineEdit->setValue(m_values.first);
218     }
219   }
220 }
221 
222 //-----------------------------------------------------------------------------
223 
setValues(const std::pair<double,double> & values)224 void DoubleValuePairField::setValues(const std::pair<double, double> &values) {
225   assert(values.first <= values.second);
226   m_values.first = tcrop(values.first, m_minValue, m_maxValue);
227   m_leftLineEdit->setValue(m_values.first);
228 
229   m_values.second = values.second;
230   if (m_isMaxRangeLimited)
231     m_values.second = tcrop(values.second, m_values.first, m_maxValue);
232   m_rightLineEdit->setValue(m_values.second);
233 
234   update();
235 }
236 
237 //-----------------------------------------------------------------------------
238 
setRange(double minValue,double maxValue)239 void DoubleValuePairField::setRange(double minValue, double maxValue) {
240   m_minValue = minValue;
241   m_maxValue = maxValue;
242 
243   if (!m_isMaxRangeLimited) maxValue = (std::numeric_limits<int>::max)();
244 
245   m_leftLineEdit->setRange(minValue, maxValue);
246   m_rightLineEdit->setRange(minValue, maxValue);
247   update();
248 }
249 
250 //-----------------------------------------------------------------------------
251 
getRange(double & minValue,double & maxValue)252 void DoubleValuePairField::getRange(double &minValue, double &maxValue) {
253   minValue = m_minValue;
254   maxValue = m_maxValue;
255 }
256 
257 //-----------------------------------------------------------------------------
258 
mousePressEvent(QMouseEvent * event)259 void DoubleValuePairField::mousePressEvent(QMouseEvent *event) {
260   if (event->button() == Qt::LeftButton) {
261     int x = event->pos().x();
262     int cur0, cur1;
263     if (m_values.first > m_maxValue)
264       cur0 = value2pos(m_maxValue) - 5;
265     else
266       cur0 = value2pos(m_values.first);
267     if (m_values.second > m_maxValue)
268       cur1 = value2pos(m_maxValue);
269     else
270       cur1 = value2pos(m_values.second);
271     int d0 = abs(cur0 - x);
272     int d1 = abs(cur1 - x);
273     int d, cur;
274     if (d0 < d1 || (d0 == d1 && x < cur0)) {
275       d           = abs(d0);
276       cur         = cur0;
277       m_grabIndex = 0;
278     } else {
279       d           = abs(d1);
280       cur         = cur1;
281       m_grabIndex = 1;
282     }
283     if (d < 6)
284       m_grabOffset = cur - x;
285     else {
286       m_grabOffset = 0;
287       setValue(pos2value(x));
288       emit valuesChanged(true);
289       update();
290     }
291   }
292 }
293 
294 //-----------------------------------------------------------------------------
295 
mouseMoveEvent(QMouseEvent * event)296 void DoubleValuePairField::mouseMoveEvent(QMouseEvent *event) {
297   if (event->buttons()) {
298     std::pair<double, double> oldValues = m_values;
299     int x                               = event->pos().x() + m_grabOffset;
300     setValue(pos2value(x));
301     if (oldValues != m_values) {
302       emit valuesChanged(true);
303       update();
304     }
305   }
306 }
307 
308 //-----------------------------------------------------------------------------
309 
mouseReleaseEvent(QMouseEvent * event)310 void DoubleValuePairField::mouseReleaseEvent(QMouseEvent *event) {
311   m_grabOffset = 0;
312   m_grabIndex  = 0;
313   emit valuesChanged(false);
314 }
315 
316 //-----------------------------------------------------------------------------
317 
onLeftEditingFinished()318 void DoubleValuePairField::onLeftEditingFinished() {
319   double value = m_leftLineEdit->getValue();
320   if (value == m_values.first) return;
321   if (!m_isMaxRangeLimited && value < m_minValue)
322     value = m_minValue;
323   else if (m_isMaxRangeLimited)
324     value = tcrop(value, m_minValue, m_maxValue);
325   m_values.first = value;
326   if (m_values.first > m_values.second) {
327     m_values.second = m_values.first;
328     m_rightLineEdit->setValue(m_values.second);
329   }
330   emit valuesChanged(false);
331   update();
332 }
333 
334 //-----------------------------------------------------------------------------
335 
onRightEditingFinished()336 void DoubleValuePairField::onRightEditingFinished() {
337   double value = m_rightLineEdit->getValue();
338   if (value == m_values.second) return;
339   if (m_isMaxRangeLimited) value = tcrop(value, m_minValue, m_maxValue);
340   m_values.second = value;
341   if (m_values.second < m_values.first) {
342     m_values.first = m_values.second;
343     m_leftLineEdit->setValue(m_values.first);
344   }
345   emit valuesChanged(false);
346   update();
347 }
348 
349 //=============================================================================
350 // DoublePairField
351 //-----------------------------------------------------------------------------
352 
DoublePairField(QWidget * parent,bool isMaxRangeLimited)353 DoublePairField::DoublePairField(QWidget *parent, bool isMaxRangeLimited)
354     : DoubleValuePairField(parent, isMaxRangeLimited, new DoubleLineEdit(0),
355                            new DoubleLineEdit(0)) {
356   DoubleLineEdit *leftLineEdit = dynamic_cast<DoubleLineEdit *>(m_leftLineEdit);
357   leftLineEdit->setDecimals(2);
358   DoubleLineEdit *rightLineEdit =
359       dynamic_cast<DoubleLineEdit *>(m_rightLineEdit);
360   rightLineEdit->setDecimals(2);
361 }
362 
363 //=============================================================================
364 // MeasuredDoublePairField
365 //-----------------------------------------------------------------------------
366 
MeasuredDoublePairField(QWidget * parent,bool isMaxRangeLimited)367 MeasuredDoublePairField::MeasuredDoublePairField(QWidget *parent,
368                                                  bool isMaxRangeLimited)
369     : DoubleValuePairField(parent, isMaxRangeLimited,
370                            new MeasuredDoubleLineEdit(0),
371                            new MeasuredDoubleLineEdit(0)) {
372   m_leftLineEdit->setFixedSize(63, WidgetHeight);
373   m_rightLineEdit->setFixedSize(63, WidgetHeight);
374 }
375 
376 //-----------------------------------------------------------------------------
377 
setMeasure(std::string measureName)378 void MeasuredDoublePairField::setMeasure(std::string measureName) {
379   MeasuredDoubleLineEdit *leftLineEdit =
380       dynamic_cast<MeasuredDoubleLineEdit *>(m_leftLineEdit);
381   assert(leftLineEdit);
382   leftLineEdit->setMeasure(measureName);
383   MeasuredDoubleLineEdit *rightLineEdit =
384       dynamic_cast<MeasuredDoubleLineEdit *>(m_rightLineEdit);
385   assert(rightLineEdit);
386   rightLineEdit->setMeasure(measureName);
387 }
388 
389 //-----------------------------------------------------------------------------
390 /*--設定ファイルからインタフェースの精度を変える--*/
setPrecision(int precision)391 void MeasuredDoublePairField::setPrecision(int precision) {
392   MeasuredDoubleLineEdit *leftLineEdit =
393       dynamic_cast<MeasuredDoubleLineEdit *>(m_leftLineEdit);
394   if (leftLineEdit) leftLineEdit->setDecimals(precision);
395   MeasuredDoubleLineEdit *rightLineEdit =
396       dynamic_cast<MeasuredDoubleLineEdit *>(m_rightLineEdit);
397   if (rightLineEdit) rightLineEdit->setDecimals(precision);
398 }
399