]> git.sesse.net Git - kdenlive/blob - src/dragvalue.cpp
Fix indent
[kdenlive] / src / dragvalue.cpp
1 /***************************************************************************
2  *   Copyright (C) 2011 by Till Theato (root@ttill.de)                     *
3  *   Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
4  *   This file is part of Kdenlive (www.kdenlive.org).                     *
5  *                                                                         *
6  *   Kdenlive is free software: you can redistribute it and/or modify      *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation, either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   Kdenlive is distributed in the hope that it will be useful,           *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with Kdenlive.  If not, see <http://www.gnu.org/licenses/>.     *
18  ***************************************************************************/
19
20 #include "dragvalue.h"
21 #include "kdenlivesettings.h"
22
23 #include <math.h>
24
25 #include <QHBoxLayout>
26 #include <QToolButton>
27 #include <QLineEdit>
28 #include <QDoubleValidator>
29 #include <QIntValidator>
30 #include <QMouseEvent>
31 #include <QFocusEvent>
32 #include <QWheelEvent>
33 #include <QApplication>
34 #include <QMenu>
35 #include <QAction>
36 #include <QLabel>
37 #include <QPainter>
38 #include <QStyle>
39
40 #include <KDebug>
41 #include <KIcon>
42 #include <KLocalizedString>
43 #include <KGlobalSettings>
44
45
46 DragValue::DragValue(const QString &label, double defaultValue, int decimals, double min, double max, int id, const QString &suffix, bool showSlider, QWidget* parent) :
47     QWidget(parent),
48     m_maximum(max),
49     m_minimum(min),
50     m_decimals(decimals),
51     m_default(defaultValue),
52     m_id(id),
53     m_intEdit(NULL),
54     m_doubleEdit(NULL)
55 {
56     if (showSlider) setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
57     else setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
58     setFocusPolicy(Qt::StrongFocus);
59     setContextMenuPolicy(Qt::CustomContextMenu);
60     setFocusPolicy(Qt::StrongFocus);
61     
62     QHBoxLayout *l = new QHBoxLayout;
63     l->setSpacing(0);
64     l->setContentsMargins(0, 0, 0, 0);
65     m_label = new CustomLabel(label, showSlider, m_maximum - m_minimum, this);
66     l->addWidget(m_label);
67     if (decimals == 0) {
68         m_label->setMaximum(max - min);
69         m_label->setStep(1);
70         m_intEdit = new QSpinBox(this);
71         m_intEdit->setObjectName("dragBox");
72         m_intEdit->setFocusPolicy(Qt::StrongFocus);
73         if (!suffix.isEmpty()) m_intEdit->setSuffix(suffix);
74         m_intEdit->setKeyboardTracking(false);
75         m_intEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
76         m_intEdit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
77         m_intEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
78         m_intEdit->setRange((int) m_minimum, (int)m_maximum);
79         l->addWidget(m_intEdit);
80         connect(m_intEdit, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int)));
81         connect(m_intEdit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
82     } else {
83         m_doubleEdit = new QDoubleSpinBox(this);
84         m_doubleEdit->setDecimals(decimals);
85         m_doubleEdit->setFocusPolicy(Qt::StrongFocus);
86         m_doubleEdit->setObjectName("dragBox");
87         if (!suffix.isEmpty()) m_doubleEdit->setSuffix(suffix);
88         m_doubleEdit->setKeyboardTracking(false);
89         m_doubleEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
90         m_doubleEdit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
91         m_doubleEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
92         m_doubleEdit->setRange(m_minimum, m_maximum);
93         double factor = 100;
94         if (m_maximum - m_minimum > 10000) factor = 1000;
95         m_label->setStep(1);
96         m_doubleEdit->setSingleStep((m_maximum - m_minimum) / factor);
97         l->addWidget(m_doubleEdit);
98         connect(m_doubleEdit, SIGNAL(valueChanged(double)), this, SLOT(slotSetValue(double)));
99         connect(m_doubleEdit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
100     }
101     
102     connect(m_label, SIGNAL(valueChanged(double,bool)), this, SLOT(setValueFromProgress(double,bool)));
103     connect(m_label, SIGNAL(resetValue()), this, SLOT(slotReset()));
104     setLayout(l);
105     if (m_intEdit)
106         m_label->setMaximumHeight(m_intEdit->sizeHint().height());
107     else
108         m_label->setMaximumHeight(m_doubleEdit->sizeHint().height());
109
110     m_menu = new QMenu(this);
111
112     m_scale = new KSelectAction(i18n("Scaling"), this);
113     m_scale->addAction(i18n("Normal scale"));
114     m_scale->addAction(i18n("Pixel scale"));
115     m_scale->addAction(i18n("Nonlinear scale"));
116     m_scale->setCurrentItem(KdenliveSettings::dragvalue_mode());
117     m_menu->addAction(m_scale);
118     
119     m_directUpdate = new QAction(i18n("Direct update"), this);
120     m_directUpdate->setCheckable(true);
121     m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
122     m_menu->addAction(m_directUpdate);
123     
124     QAction *reset = new QAction(KIcon("edit-undo"), i18n("Reset value"), this);
125     connect(reset, SIGNAL(triggered()), this, SLOT(slotReset()));
126     m_menu->addAction(reset);
127     
128     if (m_id > -1) {
129         QAction *timeline = new QAction(KIcon("go-jump"), i18n("Show %1 in timeline", label), this);
130         connect(timeline, SIGNAL(triggered()), this, SLOT(slotSetInTimeline()));
131         connect(m_label, SIGNAL(setInTimeline()), this, SLOT(slotSetInTimeline()));
132         m_menu->addAction(timeline);
133     }
134
135     connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotShowContextMenu(QPoint)));
136     connect(m_scale, SIGNAL(triggered(int)), this, SLOT(slotSetScaleMode(int)));
137     connect(m_directUpdate, SIGNAL(triggered(bool)), this, SLOT(slotSetDirectUpdate(bool)));
138 }
139
140
141 DragValue::~DragValue()
142 {
143     delete m_intEdit;
144     delete m_doubleEdit;
145     delete m_menu;
146     //delete m_scale;
147     //delete m_directUpdate;
148 }
149
150 int DragValue::spinSize()
151 {
152     if (m_intEdit)
153         return m_intEdit->sizeHint().width();
154     else
155         return m_doubleEdit->sizeHint().width();
156 }
157
158 void DragValue::setSpinSize(int width)
159 {
160     if (m_intEdit)
161         m_intEdit->setMinimumWidth(width);
162     else
163         m_doubleEdit->setMinimumWidth(width);
164 }
165
166 void DragValue::slotSetInTimeline()
167 {
168     emit inTimeline(m_id);
169 }
170
171 int DragValue::precision() const
172 {
173     return m_decimals;
174 }
175
176 qreal DragValue::maximum() const
177 {
178     return m_maximum;
179 }
180
181 qreal DragValue::minimum() const
182 {
183     return m_minimum;
184 }
185
186 qreal DragValue::value() const
187 {
188     if (m_intEdit) return m_intEdit->value();
189     else return m_doubleEdit->value();
190 }
191
192 void DragValue::setMaximum(qreal max)
193 {
194     if (m_maximum != max) {
195         m_maximum = max;
196         if (m_intEdit)
197             m_intEdit->setRange(m_minimum, m_maximum);
198         else
199             m_doubleEdit->setRange(m_minimum, m_maximum);
200     }
201 }
202
203 void DragValue::setMinimum(qreal min)
204 {
205     if (m_minimum != min) {
206         m_minimum = min;
207         if (m_intEdit)
208             m_intEdit->setRange(m_minimum, m_maximum);
209         else
210             m_doubleEdit->setRange(m_minimum, m_maximum);
211     }
212 }
213
214 void DragValue::setRange(qreal min, qreal max)
215 {
216     m_maximum = max;
217     m_minimum = min;
218     if (m_intEdit)
219         m_intEdit->setRange(m_minimum, m_maximum);
220     else
221         m_doubleEdit->setRange(m_minimum, m_maximum);
222 }
223
224 void DragValue::setPrecision(int /*precision*/)
225 {
226     //TODO: Not implemented, in case we need double value, we should replace the KIntSpinBox with KDoubleNumInput...
227     /*m_precision = precision;
228     if (precision == 0)
229         m_edit->setValidator(new QIntValidator(m_minimum, m_maximum, this));
230     else
231         m_edit->setValidator(new QDoubleValidator(m_minimum, m_maximum, precision, this));*/
232 }
233
234 void DragValue::setStep(qreal step)
235 {
236     if (m_intEdit)
237         m_intEdit->setSingleStep(step);
238     else
239         m_doubleEdit->setSingleStep(step);
240 }
241
242 void DragValue::slotReset()
243 {
244     if (m_intEdit) {
245         m_intEdit->blockSignals(true);
246         m_intEdit->setValue(m_default);
247         m_intEdit->blockSignals(false);
248         emit valueChanged((int) m_default, true);
249     }
250     else {
251         m_doubleEdit->blockSignals(true);
252         m_doubleEdit->setValue(m_default);
253         m_doubleEdit->blockSignals(false);
254         emit valueChanged(m_default, true);
255     }
256     m_label->setProgressValue((m_default - m_minimum) / (m_maximum - m_minimum) * m_label->maximum());
257 }
258
259 void DragValue::slotSetValue(int value)
260 {
261     setValue(value, true);
262 }
263
264 void DragValue::slotSetValue(double value)
265 {
266     setValue(value, true);
267 }
268
269 void DragValue::setValueFromProgress(double value, bool final)
270 {
271     value = m_minimum + value * (m_maximum - m_minimum) / m_label->maximum();
272     if (m_decimals == 0)
273         setValue(qRound(value), final);
274     else
275         setValue(value, final);
276 }
277
278 void DragValue::setValue(double value, bool final)
279 {
280     value = qBound(m_minimum, value, m_maximum);
281     if (m_intEdit) {
282         m_intEdit->blockSignals(true);
283         m_intEdit->setValue((int) value);
284         m_intEdit->blockSignals(false);
285         emit valueChanged((int) value, final);
286     }
287     else {
288         m_doubleEdit->blockSignals(true);
289         m_doubleEdit->setValue(value);
290         m_doubleEdit->blockSignals(false);
291         emit valueChanged(value, final);
292     }
293
294     m_label->setProgressValue((value - m_minimum) / (m_maximum - m_minimum) * m_label->maximum());
295 }
296
297 void DragValue::focusOutEvent(QFocusEvent*)
298 {
299     if (m_intEdit) m_intEdit->setFocusPolicy(Qt::StrongFocus);
300     else m_doubleEdit->setFocusPolicy(Qt::StrongFocus);
301 }
302
303 void DragValue::focusInEvent(QFocusEvent* e)
304 {
305     if (m_intEdit)
306         m_intEdit->setFocusPolicy(Qt::WheelFocus);
307     else
308         m_doubleEdit->setFocusPolicy(Qt::WheelFocus);
309
310     if (e->reason() == Qt::TabFocusReason || e->reason() == Qt::BacktabFocusReason) {
311         if (m_intEdit) m_intEdit->setFocus(e->reason());
312         else m_doubleEdit->setFocus(e->reason());
313     } else {
314         QWidget::focusInEvent(e);
315     }
316 }
317
318 void DragValue::slotEditingFinished()
319 {
320     if (m_intEdit) {
321         int value = m_intEdit->value();
322         m_intEdit->blockSignals(true);
323         m_intEdit->clearFocus();
324         m_intEdit->blockSignals(false);
325         if (!KdenliveSettings::dragvalue_directupdate()) emit valueChanged((double) value, true);
326     }
327     else {
328         double value = m_doubleEdit->value();
329         m_doubleEdit->blockSignals(true);
330         m_doubleEdit->clearFocus();
331         m_doubleEdit->blockSignals(false);
332         if (!KdenliveSettings::dragvalue_directupdate()) emit valueChanged(value, true);
333     }
334 }
335
336 void DragValue::slotShowContextMenu(const QPoint& pos)
337 {
338     // values might have been changed by another object of this class
339     m_scale->setCurrentItem(KdenliveSettings::dragvalue_mode());
340     m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
341     m_menu->exec(mapToGlobal(pos));
342 }
343
344 void DragValue::slotSetScaleMode(int mode)
345 {
346     KdenliveSettings::setDragvalue_mode(mode);
347 }
348
349 void DragValue::slotSetDirectUpdate(bool directUpdate)
350 {
351     KdenliveSettings::setDragvalue_directupdate(directUpdate);
352 }
353
354 void DragValue::setInTimelineProperty(bool intimeline)
355 {
356     if (m_label->property("inTimeline").toBool() == intimeline) return;
357     m_label->setProperty("inTimeline", intimeline);
358     style()->unpolish(m_label);
359     style()->polish(m_label);
360     m_label->update();
361     if (m_intEdit) {
362         m_intEdit->setProperty("inTimeline", intimeline);
363         style()->unpolish(m_intEdit);
364         style()->polish(m_intEdit);
365         m_intEdit->update();
366     }
367     else {
368         m_doubleEdit->setProperty("inTimeline", intimeline);
369         style()->unpolish(m_doubleEdit);
370         style()->polish(m_doubleEdit);
371         m_doubleEdit->update();
372     }
373     
374 }
375
376 CustomLabel::CustomLabel(const QString &label, bool showSlider, int range, QWidget* parent) :
377     QProgressBar(parent),
378     m_dragMode(false),
379     m_showSlider(showSlider),
380     m_step(10.0)
381   //m_precision(pow(10, precision)),
382 {
383     setFont(KGlobalSettings::toolBarFont());
384     setFormat(' ' + label);
385     setFocusPolicy(Qt::StrongFocus);
386     setCursor(Qt::PointingHandCursor);
387     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
388     if (showSlider) setRange(0, 1000);
389     else {
390         setRange(0, range);
391         QSize sh;
392         const QFontMetrics &fm = fontMetrics();
393         sh.setWidth(fm.width(' ' + label + ' '));
394         setMaximumWidth(sh.width());
395         setObjectName("dragOnly");
396     }
397     setValue(0);
398 }
399
400 void CustomLabel::mousePressEvent(QMouseEvent* e)
401 {
402     if (e->button() == Qt::LeftButton) {
403         m_dragStartPosition = m_dragLastPosition = e->pos();
404         e->accept();
405     }
406     else if (e->button() == Qt::MidButton) {
407         emit resetValue();
408         m_dragStartPosition = QPoint(-1, -1);
409     }
410     else QWidget::mousePressEvent(e);
411 }
412
413 void CustomLabel::mouseMoveEvent(QMouseEvent* e)
414 {
415     if (m_dragStartPosition != QPoint(-1, -1)) {
416         if (!m_dragMode && (e->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
417             m_dragMode = true;
418             m_dragLastPosition = e->pos();
419             e->accept();
420             return;
421         }
422         if (m_dragMode) {
423             if (KdenliveSettings::dragvalue_mode() > 0 || !m_showSlider) {
424                 int diff = e->x() - m_dragLastPosition.x();
425
426                 if (e->modifiers() == Qt::ControlModifier)
427                     diff *= 2;
428                 else if (e->modifiers() == Qt::ShiftModifier)
429                     diff /= 2;
430                 if (KdenliveSettings::dragvalue_mode() == 2)
431                     diff = (diff > 0 ? 1 : -1) * pow(diff, 2);
432
433                 double nv = value() + diff * m_step;
434                 if (nv != value()) setNewValue(nv, KdenliveSettings::dragvalue_directupdate());
435             }
436             else {
437                 double nv = minimum() + ((double) maximum() - minimum()) / width() * e->pos().x();
438                 if (nv != value()) setNewValue(nv, KdenliveSettings::dragvalue_directupdate());
439             }
440             m_dragLastPosition = e->pos();
441             e->accept();
442         }
443     }
444     else QWidget::mouseMoveEvent(e);
445 }
446
447 void CustomLabel::mouseReleaseEvent(QMouseEvent* e)
448 {
449     if (e->button() == Qt::MidButton) {
450         e->accept();
451         return;
452     }
453     if (e->modifiers() == Qt::ControlModifier) {
454         emit setInTimeline();
455         e->accept();
456         return;
457     }
458     if (m_dragMode) {
459         setNewValue(value(), true);
460         m_dragLastPosition = m_dragStartPosition;
461         e->accept();
462     }
463     else if (m_showSlider) {
464         setNewValue((double) maximum() * e->pos().x() / width(), true);
465         m_dragLastPosition = m_dragStartPosition;
466         e->accept();
467     }
468     m_dragMode = false;
469 }
470
471 void CustomLabel::wheelEvent(QWheelEvent* e)
472 {
473     if (e->delta() > 0) {
474         if (e->modifiers() == Qt::ControlModifier) slotValueInc(10);
475         else if (e->modifiers() == Qt::AltModifier) slotValueInc(0.1);
476         else slotValueInc();
477     }
478     else {
479         if (e->modifiers() == Qt::ControlModifier) slotValueDec(10);
480         else if (e->modifiers() == Qt::AltModifier) slotValueDec(0.1);
481         else slotValueDec();
482     }
483     e->accept();
484 }
485
486 void CustomLabel::slotValueInc(double factor)
487 {
488     setNewValue(value() + m_step * factor, true);
489 }
490
491 void CustomLabel::slotValueDec(double factor)
492 {
493     setNewValue(value() - m_step * factor, true);
494 }
495
496 void CustomLabel::setProgressValue(double value)
497 {
498     setValue(qRound(value));
499 }
500
501 void CustomLabel::setNewValue(double value, bool update)
502 {
503     setValue(qRound(value));
504     emit valueChanged(qRound(value), update);
505 }
506
507 void CustomLabel::setStep(double step)
508 {
509     m_step = step;
510 }
511
512 void CustomLabel::focusInEvent(QFocusEvent*)
513 {
514     setFocusPolicy(Qt::WheelFocus);
515 }
516
517 void CustomLabel::focusOutEvent(QFocusEvent*)
518 {
519     setFocusPolicy(Qt::StrongFocus);
520 }
521
522 #include "dragvalue.moc"