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). *
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. *
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. *
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 ***************************************************************************/
20 #include "dragvalue.h"
21 #include "kdenlivesettings.h"
25 #include <QHBoxLayout>
26 #include <QToolButton>
28 #include <QDoubleValidator>
29 #include <QIntValidator>
30 #include <QMouseEvent>
31 #include <QFocusEvent>
32 #include <QWheelEvent>
33 #include <QApplication>
41 #include <KLocalizedString>
42 #include <KGlobalSettings>
45 DragValue::DragValue(const QString &label, double defaultValue, int decimals, int id, const QString suffix, bool showSlider, QWidget* parent) :
50 m_default(defaultValue),
55 if (showSlider) setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
56 else setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
57 setFocusPolicy(Qt::StrongFocus);
58 setContextMenuPolicy(Qt::CustomContextMenu);
60 QHBoxLayout *l = new QHBoxLayout;
62 l->setContentsMargins(0, 0, 0, 0);
63 m_label = new CustomLabel(label, showSlider, decimals, this);
64 m_label->setCursor(Qt::PointingHandCursor);
65 m_label->setRange(m_minimum, m_maximum);
66 l->addWidget(m_label);
68 m_intEdit = new QSpinBox(this);
69 m_intEdit->setObjectName("dragBox");
70 if (!suffix.isEmpty()) m_intEdit->setSuffix(suffix);
71 m_intEdit->setKeyboardTracking(false);
72 m_intEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
73 m_intEdit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
74 m_intEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
75 m_intEdit->setRange((int) m_minimum, (int)m_maximum);
76 l->addWidget(m_intEdit);
77 connect(m_intEdit, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int)));
78 connect(m_intEdit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
81 m_doubleEdit = new QDoubleSpinBox(this);
82 m_doubleEdit->setDecimals(decimals);
83 m_doubleEdit->setObjectName("dragBox");
84 if (!suffix.isEmpty()) m_doubleEdit->setSuffix(suffix);
85 m_doubleEdit->setKeyboardTracking(false);
86 m_doubleEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
87 m_doubleEdit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
88 m_doubleEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
89 m_doubleEdit->setRange(m_minimum, m_maximum);
90 l->addWidget(m_doubleEdit);
91 connect(m_doubleEdit, SIGNAL(valueChanged(double)), this, SLOT(slotSetValue(double)));
92 connect(m_doubleEdit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
95 connect(m_label, SIGNAL(valueChanged(double,bool)), this, SLOT(setValue(double,bool)));
96 connect(m_label, SIGNAL(resetValue()), this, SLOT(slotReset()));
98 if (m_intEdit) m_label->setMaximumHeight(m_intEdit->sizeHint().height());
99 else m_label->setMaximumHeight(m_doubleEdit->sizeHint().height());
101 m_menu = new QMenu(this);
103 m_scale = new KSelectAction(i18n("Scaling"), this);
104 m_scale->addAction(i18n("Normal scale"));
105 m_scale->addAction(i18n("Pixel scale"));
106 m_scale->addAction(i18n("Nonlinear scale"));
107 m_scale->setCurrentItem(KdenliveSettings::dragvalue_mode());
108 m_menu->addAction(m_scale);
110 m_directUpdate = new QAction(i18n("Direct update"), this);
111 m_directUpdate->setCheckable(true);
112 m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
113 m_menu->addAction(m_directUpdate);
115 QAction *reset = new QAction(KIcon("edit-undo"), i18n("Reset value"), this);
116 connect(reset, SIGNAL(triggered()), this, SLOT(slotReset()));
117 m_menu->addAction(reset);
120 QAction *timeline = new QAction(KIcon("go-jump"), i18n("Show %1 in timeline", label), this);
121 connect(timeline, SIGNAL(triggered()), this, SLOT(slotSetInTimeline()));
122 connect(m_label, SIGNAL(setInTimeline()), this, SLOT(slotSetInTimeline()));
123 m_menu->addAction(timeline);
126 connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(slotShowContextMenu(const QPoint&)));
127 connect(m_scale, SIGNAL(triggered(int)), this, SLOT(slotSetScaleMode(int)));
128 connect(m_directUpdate, SIGNAL(triggered(bool)), this, SLOT(slotSetDirectUpdate(bool)));
132 DragValue::~DragValue()
134 if (m_intEdit) delete m_intEdit;
135 if (m_doubleEdit) delete m_doubleEdit;
138 delete m_directUpdate;
141 int DragValue::spinSize()
143 if (m_intEdit) return m_intEdit->sizeHint().width();
144 else return m_doubleEdit->sizeHint().width();
147 void DragValue::setSpinSize(int width)
149 if (m_intEdit) m_intEdit->setMinimumWidth(width);
150 else m_doubleEdit->setMinimumWidth(width);
153 void DragValue::slotSetInTimeline()
155 emit inTimeline(m_id);
158 int DragValue::precision() const
163 qreal DragValue::maximum() const
168 qreal DragValue::minimum() const
173 qreal DragValue::value() const
175 if (m_intEdit) return m_intEdit->value();
176 else return m_doubleEdit->value();
179 void DragValue::setMaximum(qreal max)
182 m_label->setRange(m_minimum, m_maximum);
183 if (m_intEdit) m_intEdit->setRange(m_minimum, m_maximum);
184 else m_doubleEdit->setRange(m_minimum, m_maximum);
187 void DragValue::setMinimum(qreal min)
190 m_label->setRange(m_minimum, m_maximum);
191 if (m_intEdit) m_intEdit->setRange(m_minimum, m_maximum);
192 else m_doubleEdit->setRange(m_minimum, m_maximum);
195 void DragValue::setRange(qreal min, qreal max)
199 m_label->setRange(m_minimum, m_maximum);
200 if (m_intEdit) m_intEdit->setRange(m_minimum, m_maximum);
201 else m_doubleEdit->setRange(m_minimum, m_maximum);
204 void DragValue::setPrecision(int /*precision*/)
206 //TODO: Not implemented, in case we need double value, we should replace the KIntSpinBox with KDoubleNumInput...
207 /*m_precision = precision;
209 m_edit->setValidator(new QIntValidator(m_minimum, m_maximum, this));
211 m_edit->setValidator(new QDoubleValidator(m_minimum, m_maximum, precision, this));*/
214 void DragValue::setStep(qreal step)
216 m_label->setStep(step);
218 m_intEdit->setSingleStep(step);
220 m_doubleEdit->setSingleStep(step);
223 void DragValue::slotReset()
226 m_intEdit->blockSignals(true);
227 m_intEdit->setValue(m_default);
228 m_intEdit->blockSignals(false);
229 emit valueChanged((int) m_default, true);
232 m_doubleEdit->blockSignals(true);
233 m_doubleEdit->setValue(m_default);
234 m_doubleEdit->blockSignals(false);
235 emit valueChanged(m_default, true);
237 m_label->setProgressValue(m_default);
240 void DragValue::slotSetValue(int value)
242 setValue(value, KdenliveSettings::dragvalue_directupdate());
245 void DragValue::slotSetValue(double value)
247 setValue(value, KdenliveSettings::dragvalue_directupdate());
250 void DragValue::setValue(double value, bool final)
252 value = qBound(m_minimum, value, m_maximum);
254 m_intEdit->blockSignals(true);
255 m_intEdit->setValue((int) value);
256 m_intEdit->blockSignals(false);
257 emit valueChanged((int) value, final);
260 m_doubleEdit->blockSignals(true);
261 m_doubleEdit->setValue(value);
262 m_doubleEdit->blockSignals(false);
263 emit valueChanged(value, final);
265 m_label->setProgressValue(value);
268 void DragValue::focusInEvent(QFocusEvent* e)
270 if (e->reason() == Qt::TabFocusReason || e->reason() == Qt::BacktabFocusReason) {
271 if (m_intEdit) m_intEdit->setFocus(e->reason());
272 else m_doubleEdit->setFocus(e->reason());
274 QWidget::focusInEvent(e);
278 void DragValue::slotEditingFinished()
281 int value = m_intEdit->value();
282 m_intEdit->blockSignals(true);
283 m_intEdit->clearFocus();
284 m_intEdit->blockSignals(false);
285 if (!KdenliveSettings::dragvalue_directupdate()) emit valueChanged(value, true);
288 double value = m_doubleEdit->value();
289 m_doubleEdit->blockSignals(true);
290 m_doubleEdit->clearFocus();
291 m_doubleEdit->blockSignals(false);
292 if (!KdenliveSettings::dragvalue_directupdate()) emit valueChanged(value, true);
296 void DragValue::slotShowContextMenu(const QPoint& pos)
298 // values might have been changed by another object of this class
299 m_scale->setCurrentItem(KdenliveSettings::dragvalue_mode());
300 m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
301 m_menu->exec(mapToGlobal(pos));
304 void DragValue::slotSetScaleMode(int mode)
306 KdenliveSettings::setDragvalue_mode(mode);
309 void DragValue::slotSetDirectUpdate(bool directUpdate)
311 KdenliveSettings::setDragvalue_directupdate(directUpdate);
314 void DragValue::setInTimelineProperty(bool intimeline)
316 if (m_label->property("inTimeline").toBool() == intimeline) return;
317 m_label->setProperty("inTimeline", intimeline);
318 style()->unpolish(m_label);
319 style()->polish(m_label);
322 m_intEdit->setProperty("inTimeline", intimeline);
323 style()->unpolish(m_intEdit);
324 style()->polish(m_intEdit);
328 m_doubleEdit->setProperty("inTimeline", intimeline);
329 style()->unpolish(m_doubleEdit);
330 style()->polish(m_doubleEdit);
331 m_doubleEdit->update();
336 CustomLabel::CustomLabel(const QString &label, bool showSlider, int precision, QWidget* parent) :
337 QProgressBar(parent),
340 m_showSlider(showSlider),
341 m_precision(pow(10, precision)),
344 setFont(KGlobalSettings::toolBarFont());
345 setFormat(" " + label);
346 setFocusPolicy(Qt::ClickFocus);
347 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
350 const QFontMetrics &fm = fontMetrics();
351 sh.setWidth(fm.width(" " + label + " "));
352 setMaximumWidth(sh.width());
353 setObjectName("dragOnly");
358 void CustomLabel::mousePressEvent(QMouseEvent* e)
360 if (e->button() == Qt::LeftButton) {
361 m_dragStartPosition = m_dragLastPosition = e->pos();
364 else if (e->button() == Qt::MidButton) {
366 m_dragStartPosition = QPoint(-1, -1);
368 else QWidget::mousePressEvent(e);
371 void CustomLabel::mouseMoveEvent(QMouseEvent* e)
373 if (m_dragStartPosition != QPoint(-1, -1)) {
374 if (!m_dragMode && (e->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
376 m_dragLastPosition = e->pos();
381 if (KdenliveSettings::dragvalue_mode() > 0 || !m_showSlider) {
382 int diff = e->x() - m_dragLastPosition.x();
384 if (e->modifiers() == Qt::ControlModifier)
386 else if (e->modifiers() == Qt::ShiftModifier)
388 if (KdenliveSettings::dragvalue_mode() == 2)
389 diff = (diff > 0 ? 1 : -1) * pow(diff, 2);
391 double nv = m_value + diff * m_step;
392 if (nv != m_value) setNewValue(nv, KdenliveSettings::dragvalue_directupdate());
395 double nv = minimum() + ((double) maximum() - minimum()) / width() * e->pos().x();
396 if (nv != m_value) setNewValue(nv, KdenliveSettings::dragvalue_directupdate());
398 m_dragLastPosition = e->pos();
402 else QWidget::mouseMoveEvent(e);
405 void CustomLabel::mouseReleaseEvent(QMouseEvent* e)
407 if (e->button() == Qt::MidButton) {
411 if (e->modifiers() == Qt::ControlModifier) {
412 emit setInTimeline();
417 setNewValue(m_value, true);
418 m_dragLastPosition = m_dragStartPosition;
421 else if (m_showSlider) {
422 setNewValue((minimum() + ((double)maximum() - minimum()) / width() * e->pos().x()), true);
423 m_dragLastPosition = m_dragStartPosition;
429 void CustomLabel::wheelEvent(QWheelEvent* e)
431 if (e->delta() > 0) {
432 if (e->modifiers() == Qt::ControlModifier) slotValueInc(m_step * 10);
433 else if (e->modifiers() == Qt::AltModifier) slotValueInc(m_step / m_precision);
437 if (e->modifiers() == Qt::ControlModifier) slotValueDec(m_step * 10);
438 else if (e->modifiers() == Qt::AltModifier) slotValueDec(m_step / m_precision);
444 void CustomLabel::slotValueInc(double factor)
446 setNewValue(m_value + m_step * factor, true);
449 void CustomLabel::slotValueDec(double factor)
451 setNewValue(m_value - m_step * factor, true);
454 void CustomLabel::setProgressValue(double value)
457 setValue((int) value);
460 void CustomLabel::setNewValue(double value, bool update)
464 emit valueChanged(value, update);
467 void CustomLabel::setStep(double step)
472 #include "dragvalue.moc"