]> git.sesse.net Git - kdenlive/blob - src/dragvalue.cpp
drag value:
[kdenlive] / src / dragvalue.cpp
1 /***************************************************************************
2  *   Copyright (C) 2011 by Till Theato (root@ttill.de)                     *
3  *   This file is part of Kdenlive (www.kdenlive.org).                     *
4  *                                                                         *
5  *   Kdenlive is free software: you can redistribute it and/or modify      *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation, either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   Kdenlive is distributed in the hope that it will be useful,           *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with Kdenlive.  If not, see <http://www.gnu.org/licenses/>.     *
17  ***************************************************************************/
18
19 #include "dragvalue.h"
20 #include "kdenlivesettings.h"
21
22 #include <math.h>
23
24 #include <QHBoxLayout>
25 #include <QToolButton>
26 #include <QLineEdit>
27 #include <QDoubleValidator>
28 #include <QIntValidator>
29 #include <QMouseEvent>
30 #include <QFocusEvent>
31 #include <QWheelEvent>
32 #include <QApplication>
33 #include <QMenu>
34 #include <QAction>
35
36 #include <KColorScheme>
37 #include <KLocalizedString>
38
39 DragValue::DragValue(QWidget* parent) :
40         QWidget(parent),
41         m_maximum(100),
42         m_minimum(0),
43         m_precision(2),
44         m_step(1),
45         m_dragMode(false)
46 {
47     setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
48     setFocusPolicy(Qt::StrongFocus);
49     setContextMenuPolicy(Qt::CustomContextMenu);
50
51     QHBoxLayout *l = new QHBoxLayout(this);
52     l->setSpacing(0);
53     l->setMargin(0);
54
55     m_edit = new QLineEdit(this);
56     m_edit->setValidator(new QDoubleValidator(m_minimum, m_maximum, m_precision, this));
57     m_edit->setAlignment(Qt::AlignCenter);
58     m_edit->setEnabled(false);
59     l->addWidget(m_edit);
60
61     m_menu = new QMenu(this);
62
63     m_nonlinearScale = new QAction(i18n("Nonlinear scale"), this);
64     m_nonlinearScale->setCheckable(true);
65     m_nonlinearScale->setChecked(KdenliveSettings::dragvalue_nonlinear());
66     m_menu->addAction(m_nonlinearScale);
67
68     m_directUpdate = new QAction(i18n("Direct update"), this);
69     m_directUpdate->setCheckable(true);
70     m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
71     m_menu->addAction(m_directUpdate);
72
73     QPalette p = palette();
74     KColorScheme scheme(p.currentColorGroup(), KColorScheme::View, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
75     QColor bg = scheme.background(KColorScheme::LinkBackground).color();
76     QColor fg = scheme.foreground(KColorScheme::LinkText).color();
77     QColor editbg = scheme.background(KColorScheme::ActiveBackground).color();
78     QColor editfg = scheme.foreground(KColorScheme::ActiveText).color();
79     QString stylesheet(QString("QLineEdit { background-color: rgb(%1, %2, %3); border: 1px solid rgb(%1, %2, %3); border-radius: 5px; padding: 0px; color: rgb(%4, %5, %6); } QLineEdit::disabled { color: rgb(%4, %5, %6); }")
80                         .arg(bg.red()).arg(bg.green()).arg(bg.blue())
81                         .arg(fg.red()).arg(fg.green()).arg(fg.blue()));
82     stylesheet.append(QString("QLineEdit::focus, QLineEdit::enabled { background-color: rgb(%1, %2, %3); color: rgb(%4, %5, %6); }")
83                         .arg(editbg.red()).arg(editbg.green()).arg(editbg.blue())
84                         .arg(editfg.red()).arg(editfg.green()).arg(editfg.blue()));
85     setStyleSheet(stylesheet);
86
87     updateMaxWidth();
88
89     connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(slotShowContextMenu(const QPoint&)));
90     connect(m_nonlinearScale, SIGNAL(triggered(bool)), this, SLOT(slotSetNonlinearScale(bool)));
91     connect(m_directUpdate, SIGNAL(triggered(bool)), this, SLOT(slotSetDirectUpdate(bool)));
92
93     connect(m_edit, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished()));
94 }
95
96 DragValue::~DragValue()
97 {
98     delete m_edit;
99     delete m_menu;
100     delete m_nonlinearScale;
101     delete m_directUpdate;
102 }
103
104 int DragValue::precision() const
105 {
106     return m_precision;
107 }
108
109 qreal DragValue::maximum() const
110 {
111     return m_maximum;
112 }
113
114 qreal DragValue::minimum() const
115 {
116     return m_minimum;
117 }
118
119 qreal DragValue::value() const
120 {
121     return m_edit->text().toDouble();
122 }
123
124 void DragValue::setMaximum(qreal max)
125 {
126     m_maximum = max;
127     updateMaxWidth();
128 }
129
130 void DragValue::setMinimum(qreal min)
131 {
132     m_minimum = min;
133     updateMaxWidth();
134 }
135
136 void DragValue::setRange(qreal min, qreal max)
137 {
138     m_maximum = max;
139     m_minimum = min;
140     updateMaxWidth();
141 }
142
143 void DragValue::setPrecision(int precision)
144 {
145     m_precision = precision;
146     if (precision == 0)
147         m_edit->setValidator(new QIntValidator(m_minimum, m_maximum, this));
148     else
149         m_edit->setValidator(new QDoubleValidator(m_minimum, m_maximum, precision, this));
150 }
151
152 void DragValue::setStep(qreal step)
153 {
154     m_step = step;
155 }
156
157 void DragValue::setValue(qreal value, bool final)
158 {
159     value = qBound(m_minimum, value, m_maximum);
160
161     m_edit->setText(QString::number(value, 'f', m_precision));
162
163     emit valueChanged(value, final);
164 }
165
166 void DragValue::mousePressEvent(QMouseEvent* e)
167 {
168     if (e->button() == Qt::LeftButton) {
169         m_dragStartPosition = m_dragLastPosition = e->pos();
170         m_dragMode = true;
171         e->accept();
172     }
173 }
174
175 void DragValue::mouseMoveEvent(QMouseEvent* e)
176 {
177     if (m_dragMode && (e->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
178         int diff = e->x() - m_dragLastPosition.x();
179
180         if (e->modifiers() == Qt::ControlModifier)
181             diff *= 2;
182         else if (e->modifiers() == Qt::ShiftModifier)
183             diff /= 2;
184         if (KdenliveSettings::dragvalue_nonlinear())
185             diff = (diff > 0 ? 1 : -1) * pow(diff, 2);
186
187         setValue(value() + diff / m_step, KdenliveSettings::dragvalue_directupdate());
188         m_dragLastPosition = e->pos();
189         e->accept();
190     }
191 }
192
193 void DragValue::mouseReleaseEvent(QMouseEvent* e)
194 {
195     m_dragMode = false;
196     if (m_dragLastPosition == m_dragStartPosition) {
197         // value was not changed through dragging (mouse position stayed the same since mousePressEvent)
198         m_edit->setEnabled(true);
199         m_edit->setFocus(Qt::MouseFocusReason);
200     } else {
201         setValue(value(), true);
202         m_dragLastPosition = m_dragStartPosition;
203         e->accept();
204     }
205 }
206
207 void DragValue::wheelEvent(QWheelEvent* e)
208 {
209     if (e->delta() > 0)
210         slotValueInc();
211     else
212         slotValueDec();
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::slotValueInc()
226 {
227     setValue(m_edit->text().toDouble() + m_step);
228 }
229
230 void DragValue::slotValueDec()
231 {
232     setValue(m_edit->text().toDouble() - m_step);
233 }
234
235 void DragValue::slotEditingFinished()
236 {
237     qreal value = m_edit->text().toDouble();
238     m_edit->setEnabled(false);
239     emit valueChanged(value, true);
240 }
241
242 void DragValue::updateMaxWidth()
243 {
244     int val = (int)(log10(qAbs(m_maximum) > qAbs(m_minimum) ? qAbs(m_maximum) : qAbs(m_minimum)) + .5);
245     val += m_precision;
246     if (m_precision)
247         val += 1;
248     if (m_minimum < 0)
249         val += 1;
250     QFontMetrics fm = m_edit->fontMetrics();
251     m_edit->setMaximumWidth(fm.width(QString().rightJustified(val, '8')));
252 }
253
254 void DragValue::slotShowContextMenu(const QPoint& pos)
255 {
256     // values might have been changed by another object of this class
257     m_nonlinearScale->setChecked(KdenliveSettings::dragvalue_nonlinear());
258     m_directUpdate->setChecked(KdenliveSettings::dragvalue_directupdate());
259     m_menu->exec(mapToGlobal(pos));
260 }
261
262 void DragValue::slotSetNonlinearScale(bool nonlinear)
263 {
264     KdenliveSettings::setDragvalue_nonlinear(nonlinear);
265 }
266
267 void DragValue::slotSetDirectUpdate(bool directUpdate)
268 {
269     KdenliveSettings::setDragvalue_directupdate(directUpdate);
270 }
271
272 #include "dragvalue.moc"