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