1 /* This file is part of the KDE project
2 SPDX-FileCopyrightText: 2010 Jean-Baptiste Mardelle <jb@kdenlive.org>
3
4 SPDX-License-Identifier: LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7 #include "timecodedisplay.h"
8 #include "kdenlivesettings.h"
9
10 #include <QFontDatabase>
11 #include <QLineEdit>
12 #include <QMouseEvent>
13 #include <QStyle>
14
15 #include <KColorScheme>
16
MyValidator(QObject * parent)17 MyValidator::MyValidator(QObject *parent)
18 : QValidator(parent)
19 {
20 }
21
fixup(QString & str) const22 void MyValidator::fixup(QString &str) const
23 {
24 str.replace(QLatin1Char(' '), QLatin1Char('0'));
25 }
26
validate(QString & str,int &) const27 QValidator::State MyValidator::validate(QString &str, int &) const
28 {
29 if (str.contains(QLatin1Char(' '))) {
30 fixup(str);
31 }
32 return QValidator::Acceptable;
33 }
34
TimecodeDisplay(const Timecode & t,QWidget * parent)35 TimecodeDisplay::TimecodeDisplay(const Timecode &t, QWidget *parent)
36 : QAbstractSpinBox(parent)
37 , m_timecode(t)
38 , m_frametimecode(false)
39 , m_minimum(0)
40 , m_maximum(-1)
41 , m_value(0)
42 , m_offset(0)
43 {
44 const QFont ft = QFontDatabase::systemFont(QFontDatabase::FixedFont);
45 lineEdit()->setFont(ft);
46 setFont(ft);
47 lineEdit()->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
48 QFontMetrics fm(ft);
49 setFrame(false);
50 QPalette palette;
51 palette.setColor(QPalette::Base, Qt::transparent); // palette.window().color());
52 setPalette(palette);
53 setTimeCodeFormat(KdenliveSettings::frametimecode(), true);
54 setValue(m_minimum);
55 setMinimumWidth(fm.horizontalAdvance(QStringLiteral("88:88:88:88")) + contentsMargins().right() + contentsMargins().left() + frameSize().width() -
56 lineEdit()->contentsRect().width() + (int)QStyle::PM_SpinBoxFrameWidth + 6);
57
58 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);
59 setAccelerated(true);
60 connect(lineEdit(), &QLineEdit::editingFinished, this, &TimecodeDisplay::slotEditingFinished, Qt::DirectConnection);
61 }
62
63 // virtual protected
stepEnabled() const64 QAbstractSpinBox::StepEnabled TimecodeDisplay::stepEnabled() const
65 {
66 QAbstractSpinBox::StepEnabled result = QAbstractSpinBox::StepNone;
67 if (m_value > m_minimum) {
68 result |= QAbstractSpinBox::StepDownEnabled;
69 }
70 if (m_maximum == -1 || m_value < m_maximum) {
71 result |= QAbstractSpinBox::StepUpEnabled;
72 }
73 return result;
74 }
75
76 // virtual
stepBy(int steps)77 void TimecodeDisplay::stepBy(int steps)
78 {
79 int val = m_value + steps;
80 setValue(val);
81 }
82
setTimeCodeFormat(bool frametimecode,bool init)83 void TimecodeDisplay::setTimeCodeFormat(bool frametimecode, bool init)
84 {
85 if (!init && m_frametimecode == frametimecode) {
86 return;
87 }
88 m_frametimecode = frametimecode;
89 lineEdit()->clear();
90 if (m_frametimecode) {
91 auto *valid = new QIntValidator(lineEdit());
92 valid->setBottom(0);
93 lineEdit()->setValidator(valid);
94 lineEdit()->setInputMask(QString());
95 } else {
96 lineEdit()->setInputMask(m_timecode.mask());
97 auto *valid = new MyValidator(lineEdit());
98 lineEdit()->setValidator(valid);
99 }
100 setValue(m_value);
101 }
102
slotUpdateTimeCodeFormat()103 void TimecodeDisplay::slotUpdateTimeCodeFormat()
104 {
105 setTimeCodeFormat(KdenliveSettings::frametimecode());
106 }
107
updateTimeCode(const Timecode & t)108 void TimecodeDisplay::updateTimeCode(const Timecode &t)
109 {
110 m_timecode = t;
111 setTimeCodeFormat(KdenliveSettings::frametimecode(), true);
112 }
113
keyPressEvent(QKeyEvent * e)114 void TimecodeDisplay::keyPressEvent(QKeyEvent *e)
115 {
116 if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
117 e->setAccepted(true);
118 clearFocus();
119 } else {
120 QAbstractSpinBox::keyPressEvent(e);
121 }
122 }
123
mouseReleaseEvent(QMouseEvent * e)124 void TimecodeDisplay::mouseReleaseEvent(QMouseEvent *e)
125 {
126 QAbstractSpinBox::mouseReleaseEvent(e);
127 if (!lineEdit()->underMouse()) {
128 clearFocus();
129 }
130 }
131
wheelEvent(QWheelEvent * e)132 void TimecodeDisplay::wheelEvent(QWheelEvent *e)
133 {
134 QAbstractSpinBox::wheelEvent(e);
135 if (hasFocus()) {
136 clearFocus();
137 } else {
138 slotEditingFinished();
139 }
140 }
141
enterEvent(QEvent * e)142 void TimecodeDisplay::enterEvent(QEvent *e)
143 {
144 QAbstractSpinBox::enterEvent(e);
145 setFrame(true);
146 }
147
leaveEvent(QEvent * e)148 void TimecodeDisplay::leaveEvent(QEvent *e)
149 {
150 QAbstractSpinBox::leaveEvent(e);
151 setFrame(false);
152 }
153
maximum() const154 int TimecodeDisplay::maximum() const
155 {
156 return m_maximum;
157 }
158
minimum() const159 int TimecodeDisplay::minimum() const
160 {
161 return m_minimum;
162 }
163
getValue() const164 int TimecodeDisplay::getValue() const
165 {
166 return m_value;
167 }
168
gentime() const169 GenTime TimecodeDisplay::gentime() const
170 {
171 return {m_value, m_timecode.fps()};
172 }
173
timecode() const174 Timecode TimecodeDisplay::timecode() const
175 {
176 return m_timecode;
177 }
178
setRange(int min,int max)179 void TimecodeDisplay::setRange(int min, int max)
180 {
181 m_minimum = min;
182 m_maximum = max;
183 }
184
setValue(const QString & value)185 void TimecodeDisplay::setValue(const QString &value)
186 {
187 setValue(m_timecode.getFrameCount(value));
188 }
189
setValue(int value)190 void TimecodeDisplay::setValue(int value)
191 {
192 if (m_maximum > 0) {
193 value = qBound(m_minimum, value, m_maximum);
194 } else {
195 value = qMax(m_minimum, value);
196 }
197
198 if (m_frametimecode) {
199 if (value == m_value && !lineEdit()->text().isEmpty()) {
200 return;
201 }
202 m_value = value;
203 lineEdit()->setText(QString::number(value - m_minimum));
204 } else {
205 if (value == m_value && lineEdit()->text() != QLatin1String(":::")) {
206 return;
207 }
208 m_value = value;
209 lineEdit()->setText(m_timecode.getTimecodeFromFrames(m_offset + value - m_minimum));
210 }
211 emit timeCodeUpdated();
212 }
213
setValue(const GenTime & value)214 void TimecodeDisplay::setValue(const GenTime &value)
215 {
216 setValue((int)value.frames(m_timecode.fps()));
217 }
218
slotEditingFinished()219 void TimecodeDisplay::slotEditingFinished()
220 {
221 lineEdit()->deselect();
222 if (m_frametimecode) {
223 setValue(lineEdit()->text().toInt() + m_minimum);
224 } else {
225 setValue(m_timecode.getFrameCount(lineEdit()->text()) + m_minimum - m_offset);
226 }
227 emit timeCodeEditingFinished(m_value);
228 }
229
displayText() const230 const QString TimecodeDisplay::displayText() const
231 {
232 return lineEdit()->displayText();
233 }
234
selectAll()235 void TimecodeDisplay::selectAll()
236 {
237 lineEdit()->selectAll();
238 }
239
setOffset(int offset)240 void TimecodeDisplay::setOffset(int offset)
241 {
242 m_offset = GenTime(offset/1000.).frames(m_timecode.fps());
243 // Update timecode display
244 if (!m_frametimecode) {
245 lineEdit()->setText(m_timecode.getTimecodeFromFrames(m_offset + m_value - m_minimum));
246 emit timeCodeUpdated();
247 }
248 }
249