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