]> git.sesse.net Git - kdenlive/blob - src/dragvalue.cpp
Fix parameter update when Direct update is not enabled
[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 <KIcon>
41 #include <KLocalizedString>
42 #include <KGlobalSettings>
43
44 DragValue::DragValue(const QString &label, int defaultValue, int id, const QString suffix, QWidget* parent) :
45         QWidget(parent),
46         m_maximum(100),
47         m_minimum(0),
48         m_precision(2),
49         m_default(defaultValue),
50         m_id(id)
51 {
52     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
53     setFocusPolicy(Qt::StrongFocus);
54     setContextMenuPolicy(Qt::CustomContextMenu);
55     
56     QHBoxLayout *l = new QHBoxLayout;
57     l->setSpacing(0);
58     l->setContentsMargins(0, 0, 0, 0);
59     m_label = new CustomLabel(label, this);
60     m_label->setCursor(Qt::PointingHandCursor);
61     m_label->setRange(m_minimum, m_maximum);
62     l->addWidget(m_label);
63     m_edit = new KIntSpinBox(this);
64     if (!suffix.isEmpty()) m_edit->setSuffix(suffix);
65
66     m_edit->setButtonSymbols(QAbstractSpinBox::NoButtons);
67     m_edit->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
68     m_edit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
69     m_edit->setRange(m_minimum, m_maximum);
70     l->addWidget(m_edit);
71     connect(m_edit, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int)));
72     connect(m_label, SIGNAL(valueChanged(int,bool)), this, SLOT(setValue(int,bool)));
73     setLayout(l);
74     m_label->setMaximumHeight(m_edit->sizeHint().height());
75
76     m_menu = new QMenu(this);
77   
78     m_scale = new KSelectAction(i18n("Scaling"), this);
79     m_scale->addAction(i18n("Normal scale"));
80     m_scale->addAction(i18n("Pixel scale"));
81     m_scale->addAction(i18n("Nonlinear scale"));
82     m_scale->setCurrentItem(KdenliveSettings::dragvalue_mode());
83     m_menu->addAction(m_scale);
84     
85     m_directUpdate = new QAction(i18n("Direct update"), this);
86     m_directUpdate->setCheckable(true);
87     m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
88     m_menu->addAction(m_directUpdate);
89     
90     QAction *reset = new QAction(KIcon("edit-undo"), i18n("Reset value"), this);
91     connect(reset, SIGNAL(triggered()), this, SLOT(slotReset()));
92     m_menu->addAction(reset);
93     
94     if (m_id > -1) {
95         QAction *timeline = new QAction(KIcon("go-jump"), i18n("Show %1 in timeline", label), this);
96         connect(timeline, SIGNAL(triggered()), this, SLOT(slotSetInTimeline()));
97         connect(m_label, SIGNAL(setInTimeline()), this, SLOT(slotSetInTimeline()));
98         m_menu->addAction(timeline);
99     }
100                         
101     m_label->setRange(m_minimum, m_maximum);
102
103     connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(slotShowContextMenu(const QPoint&)));
104     connect(m_scale, SIGNAL(triggered(int)), this, SLOT(slotSetScaleMode(int)));
105     connect(m_directUpdate, SIGNAL(triggered(bool)), this, SLOT(slotSetDirectUpdate(bool)));
106
107     connect(m_edit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
108 }
109
110 DragValue::~DragValue()
111 {
112     delete m_edit;
113     delete m_menu;
114     delete m_scale;
115     delete m_directUpdate;
116 }
117
118 int DragValue::spinSize()
119 {
120     return m_edit->sizeHint().width();
121 }
122
123 void DragValue::setSpinSize(int width)
124 {
125     m_edit->setMinimumWidth(width);
126 }
127
128 void DragValue::slotSetInTimeline()
129 {
130     emit inTimeline(m_id);
131 }
132
133 int DragValue::precision() const
134 {
135     return m_precision;
136 }
137
138 qreal DragValue::maximum() const
139 {
140     return m_maximum;
141 }
142
143 qreal DragValue::minimum() const
144 {
145     return m_minimum;
146 }
147
148 qreal DragValue::value() const
149 {
150     return m_edit->value();
151 }
152
153 void DragValue::setMaximum(qreal max)
154 {
155     m_maximum = max;
156     m_label->setRange(m_minimum, m_maximum);
157     m_edit->setRange(m_minimum, m_maximum);
158 }
159
160 void DragValue::setMinimum(qreal min)
161 {
162     m_minimum = min;
163     m_label->setRange(m_minimum, m_maximum);
164     m_edit->setRange(m_minimum, m_maximum);
165 }
166
167 void DragValue::setRange(qreal min, qreal max)
168 {
169     m_maximum = max;
170     m_minimum = min;
171     m_label->setRange(m_minimum, m_maximum);
172     m_edit->setRange(m_minimum, m_maximum);
173 }
174
175 void DragValue::setPrecision(int /*precision*/)
176 {
177     //TODO: Not implemented, in case we need double value, we should replace the KIntSpinBox with KDoubleNumInput...
178     /*m_precision = precision;
179     if (precision == 0)
180         m_edit->setValidator(new QIntValidator(m_minimum, m_maximum, this));
181     else
182         m_edit->setValidator(new QDoubleValidator(m_minimum, m_maximum, precision, this));*/
183 }
184
185 void DragValue::setStep(qreal /*step*/)
186 {
187     //m_step = step;
188 }
189
190 void DragValue::slotReset()
191 {
192     m_edit->blockSignals(true);
193     m_edit->setValue(m_default);
194     m_label->setValue(m_default);
195     m_edit->blockSignals(false);
196     emit valueChanged(m_default, true);
197 }
198
199 void DragValue::slotSetValue(int value)
200 {
201     setValue(value, KdenliveSettings::dragvalue_directupdate());
202 }
203
204 void DragValue::setValue(int value, bool final)
205 {
206     value = qBound(m_minimum, value, m_maximum);
207     m_edit->blockSignals(true);
208     m_edit->setValue(value);
209     m_edit->blockSignals(false);
210     m_label->setValue(value);
211     emit valueChanged(value, final);
212 }
213
214 void DragValue::focusInEvent(QFocusEvent* e)
215 {
216     if (e->reason() == Qt::TabFocusReason || e->reason() == Qt::BacktabFocusReason) {
217         //m_edit->setEnabled(true);
218         m_edit->setFocus(e->reason());
219     } else {
220         QWidget::focusInEvent(e);
221     }
222 }
223
224 void DragValue::slotEditingFinished()
225 {
226     qreal value = m_edit->value();
227     m_edit->clearFocus();
228     emit valueChanged(value, true);
229 }
230
231 void DragValue::slotShowContextMenu(const QPoint& pos)
232 {
233     // values might have been changed by another object of this class
234     m_scale->setCurrentItem(KdenliveSettings::dragvalue_mode());
235     m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
236     m_menu->exec(mapToGlobal(pos));
237 }
238
239 void DragValue::slotSetScaleMode(int mode)
240 {
241     KdenliveSettings::setDragvalue_mode(mode);
242 }
243
244 void DragValue::slotSetDirectUpdate(bool directUpdate)
245 {
246     KdenliveSettings::setDragvalue_directupdate(directUpdate);
247 }
248
249 void DragValue::setInTimelineProperty(bool intimeline)
250 {
251     if (m_label->property("inTimeline").toBool() == intimeline) return;
252     m_label->setProperty("inTimeline", intimeline);
253     m_edit->setProperty("inTimeline", intimeline);
254     style()->unpolish(m_label);
255     style()->polish(m_label);
256     m_label->update();
257     style()->unpolish(m_edit);
258     style()->polish(m_edit);
259     m_edit->update();
260 }
261
262 CustomLabel::CustomLabel(const QString &label, QWidget* parent) :
263     QProgressBar(parent),
264     m_dragMode(false),
265     m_step(1)
266
267 {
268     setFormat(" " + label);
269     setFocusPolicy(Qt::ClickFocus);
270     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
271     setRange(0, 100);
272     setValue(0);
273     setFont(KGlobalSettings::toolBarFont());
274 }
275
276 void CustomLabel::mousePressEvent(QMouseEvent* e)
277 {
278     if (e->button() == Qt::LeftButton) {
279         m_dragStartPosition = m_dragLastPosition = e->pos();
280         e->accept();
281     }
282     else QWidget::mousePressEvent(e);
283 }
284
285 void CustomLabel::mouseMoveEvent(QMouseEvent* e)
286 {
287     if ((e->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
288         m_dragMode = true;
289         if (KdenliveSettings::dragvalue_mode() > 0) {
290             int diff = e->x() - m_dragLastPosition.x();
291
292             if (e->modifiers() == Qt::ControlModifier)
293                 diff *= 2;
294             else if (e->modifiers() == Qt::ShiftModifier)
295                 diff /= 2;
296             if (KdenliveSettings::dragvalue_mode() == 2)
297                 diff = (diff > 0 ? 1 : -1) * pow(diff, 2);
298
299             int nv = value() + diff / m_step;
300             if (nv != value()) setNewValue(nv, KdenliveSettings::dragvalue_directupdate());
301         }
302         else {
303             int nv = minimum() + ((double) maximum() - minimum()) / width() * e->pos().x();
304             if (nv != value()) setNewValue(nv, KdenliveSettings::dragvalue_directupdate());
305         }
306         m_dragLastPosition = e->pos();
307         e->accept();
308     }
309     else QWidget::mouseMoveEvent(e);
310 }
311
312 void CustomLabel::mouseReleaseEvent(QMouseEvent* e)
313 {
314     if (e->modifiers() == Qt::ControlModifier) {
315         emit setInTimeline();
316         e->accept();
317         return;
318     }
319     if (m_dragMode) {
320         setNewValue(value(), true);
321         m_dragLastPosition = m_dragStartPosition;
322         e->accept();
323     }
324     else {
325         setNewValue((int) (minimum() + ((double)maximum() - minimum()) / width() * e->pos().x()), true);
326         m_dragLastPosition = m_dragStartPosition;
327         e->accept();
328     }
329     m_dragMode = false;
330 }
331
332 void CustomLabel::wheelEvent(QWheelEvent* e)
333 {
334     if (e->delta() > 0) {
335         if (e->modifiers() == Qt::ControlModifier) slotValueInc(10);
336         else slotValueInc();
337     }
338     else {
339         if (e->modifiers() == Qt::ControlModifier) slotValueDec(10);
340         else slotValueDec();
341     }
342     e->accept();
343 }
344
345 void CustomLabel::slotValueInc(int factor)
346 {
347     setNewValue((int) (value() + m_step * factor), true);
348 }
349
350 void CustomLabel::slotValueDec(int factor)
351 {
352     setNewValue((int) (value() - m_step * factor), true);
353 }
354
355 void CustomLabel::setNewValue(int value, bool update)
356 {
357     setValue(value);
358     emit valueChanged(value, update);
359 }
360
361 #include "dragvalue.moc"
362