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