File indexing completed on 2024-04-21 08:42:24

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2010 Jean-Baptiste Mardelle <jb@kdenlive.org>
0003 
0004     SPDX-License-Identifier: LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "timecodedisplay.h"
0008 #include "core.h"
0009 #include "kdenlivesettings.h"
0010 
0011 #include <QFontDatabase>
0012 #include <QLineEdit>
0013 #include <QMouseEvent>
0014 #include <QStyle>
0015 
0016 #include <KColorScheme>
0017 
0018 TimecodeValidator::TimecodeValidator(QObject *parent)
0019     : QValidator(parent)
0020 {
0021 }
0022 
0023 void TimecodeValidator::fixup(QString &str) const
0024 {
0025     str.replace(QLatin1Char(' '), QLatin1Char('0'));
0026 }
0027 
0028 QValidator::State TimecodeValidator::validate(QString &str, int &) const
0029 {
0030     if (str.contains(QLatin1Char(' '))) {
0031         fixup(str);
0032     }
0033     return QValidator::Acceptable;
0034 }
0035 
0036 TimecodeDisplay::TimecodeDisplay(QWidget *parent, bool autoAdjust)
0037     : TimecodeDisplay(parent, (pCore && autoAdjust) ? pCore->timecode() : Timecode())
0038 {
0039     if (pCore && autoAdjust) {
0040         connect(pCore.get(), &Core::updateProjectTimecode, this, &TimecodeDisplay::refreshTimeCode);
0041     }
0042 }
0043 
0044 TimecodeDisplay::TimecodeDisplay(QWidget *parent, const Timecode &t)
0045     : QAbstractSpinBox(parent)
0046     , m_timecode(t)
0047     , m_frametimecode(false)
0048     , m_minimum(0)
0049     , m_maximum(-1)
0050     , m_value(0)
0051     , m_offset(0)
0052 {
0053     const QFont ft = QFontDatabase::systemFont(QFontDatabase::FixedFont);
0054     lineEdit()->setFont(ft);
0055     setFont(ft);
0056     lineEdit()->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
0057     QFontMetrics fm(ft);
0058     setFrame(false);
0059     QPalette palette;
0060     palette.setColor(QPalette::Base, Qt::transparent); // palette.window().color());
0061     setPalette(palette);
0062     setTimeCodeFormat(KdenliveSettings::frametimecode(), true);
0063     setValue(m_minimum);
0064     setMinimumWidth(fm.horizontalAdvance(QStringLiteral("88:88:88:88")) + contentsMargins().right() + contentsMargins().left() + frameSize().width() -
0065                     lineEdit()->contentsRect().width() + (int)QStyle::PM_SpinBoxFrameWidth + 6);
0066 
0067     setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum);
0068     setAccelerated(true);
0069     connect(lineEdit(), &QLineEdit::editingFinished, this, &TimecodeDisplay::slotEditingFinished, Qt::DirectConnection);
0070 }
0071 
0072 // virtual protected
0073 QAbstractSpinBox::StepEnabled TimecodeDisplay::stepEnabled() const
0074 {
0075     QAbstractSpinBox::StepEnabled result = QAbstractSpinBox::StepNone;
0076     if (m_value > m_minimum) {
0077         result |= QAbstractSpinBox::StepDownEnabled;
0078     }
0079     if (m_maximum == -1 || m_value < m_maximum) {
0080         result |= QAbstractSpinBox::StepUpEnabled;
0081     }
0082     return result;
0083 }
0084 
0085 // virtual
0086 void TimecodeDisplay::stepBy(int steps)
0087 {
0088     int val = m_value + steps;
0089     setValue(val);
0090 }
0091 
0092 void TimecodeDisplay::setTimeCodeFormat(bool frametimecode, bool init)
0093 {
0094     if (!init && m_frametimecode == frametimecode) {
0095         return;
0096     }
0097     m_frametimecode = frametimecode;
0098     lineEdit()->clear();
0099     if (m_frametimecode) {
0100         auto *valid = new QIntValidator(lineEdit());
0101         valid->setBottom(0);
0102         lineEdit()->setValidator(valid);
0103         lineEdit()->setInputMask(QString());
0104     } else {
0105         lineEdit()->setInputMask(m_timecode.mask());
0106         auto *valid = new TimecodeValidator(lineEdit());
0107         lineEdit()->setValidator(valid);
0108     }
0109     setValue(m_value);
0110 }
0111 
0112 void TimecodeDisplay::updateTimeCode(const Timecode &t)
0113 {
0114     m_timecode = t;
0115     setTimeCodeFormat(KdenliveSettings::frametimecode(), true);
0116 }
0117 
0118 void TimecodeDisplay::refreshTimeCode()
0119 {
0120     updateTimeCode(pCore->timecode());
0121 }
0122 
0123 void TimecodeDisplay::keyPressEvent(QKeyEvent *e)
0124 {
0125     if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
0126         e->setAccepted(true);
0127         clearFocus();
0128     } else {
0129         QAbstractSpinBox::keyPressEvent(e);
0130     }
0131 }
0132 
0133 void TimecodeDisplay::mouseReleaseEvent(QMouseEvent *e)
0134 {
0135     QAbstractSpinBox::mouseReleaseEvent(e);
0136     if (!lineEdit()->underMouse()) {
0137         clearFocus();
0138     }
0139 }
0140 
0141 void TimecodeDisplay::wheelEvent(QWheelEvent *e)
0142 {
0143     QAbstractSpinBox::wheelEvent(e);
0144     if (hasFocus()) {
0145         clearFocus();
0146     } else {
0147         slotEditingFinished();
0148     }
0149 }
0150 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0151 void TimecodeDisplay::enterEvent(QEnterEvent *e)
0152 #else
0153 void TimecodeDisplay::enterEvent(QEvent *e)
0154 #endif
0155 {
0156     QAbstractSpinBox::enterEvent(e);
0157     setFrame(true);
0158 }
0159 
0160 void TimecodeDisplay::leaveEvent(QEvent *e)
0161 {
0162     QAbstractSpinBox::leaveEvent(e);
0163     setFrame(false);
0164 }
0165 
0166 int TimecodeDisplay::maximum() const
0167 {
0168     return m_maximum;
0169 }
0170 
0171 int TimecodeDisplay::minimum() const
0172 {
0173     return m_minimum;
0174 }
0175 
0176 int TimecodeDisplay::getValue() const
0177 {
0178     return m_value;
0179 }
0180 
0181 GenTime TimecodeDisplay::gentime() const
0182 {
0183     return {m_value, m_timecode.fps()};
0184 }
0185 
0186 Timecode TimecodeDisplay::timecode() const
0187 {
0188     return m_timecode;
0189 }
0190 
0191 void TimecodeDisplay::setTimecode(const Timecode &t)
0192 {
0193     m_timecode = t;
0194 }
0195 
0196 void TimecodeDisplay::setRange(int min, int max)
0197 {
0198     m_minimum = min;
0199     m_maximum = max;
0200 }
0201 
0202 void TimecodeDisplay::setValue(const QString &value)
0203 {
0204     setValue(m_timecode.getFrameCount(value));
0205 }
0206 
0207 void TimecodeDisplay::setValue(int value)
0208 {
0209     if (m_maximum > 0) {
0210         value = qBound(m_minimum, value, m_maximum);
0211     } else {
0212         value = qMax(m_minimum, value);
0213     }
0214 
0215     if (m_frametimecode) {
0216         if (value == m_value && !lineEdit()->text().isEmpty()) {
0217             return;
0218         }
0219         m_value = value;
0220         lineEdit()->setText(QString::number(value - m_minimum));
0221     } else {
0222         if (value == m_value && lineEdit()->text() != QLatin1String(":::")) {
0223             return;
0224         }
0225         m_value = value;
0226         lineEdit()->setText(m_timecode.getTimecodeFromFrames(m_offset + value - m_minimum));
0227     }
0228     Q_EMIT timeCodeUpdated();
0229 }
0230 
0231 void TimecodeDisplay::setValue(const GenTime &value)
0232 {
0233     setValue((int)value.frames(m_timecode.fps()));
0234 }
0235 
0236 void TimecodeDisplay::slotEditingFinished()
0237 {
0238     lineEdit()->deselect();
0239     if (m_frametimecode) {
0240         setValue(lineEdit()->text().toInt() + m_minimum);
0241     } else {
0242         setValue(m_timecode.getFrameCount(lineEdit()->text()) + m_minimum - m_offset);
0243     }
0244     Q_EMIT timeCodeEditingFinished(m_value);
0245 }
0246 
0247 const QString TimecodeDisplay::displayText() const
0248 {
0249     return lineEdit()->displayText();
0250 }
0251 
0252 void TimecodeDisplay::selectAll()
0253 {
0254     lineEdit()->selectAll();
0255 }
0256 
0257 void TimecodeDisplay::setOffset(int offset)
0258 {
0259     m_offset = GenTime(offset / 1000.).frames(m_timecode.fps());
0260     // Update timecode display
0261     if (!m_frametimecode) {
0262         lineEdit()->setText(m_timecode.getTimecodeFromFrames(m_offset + m_value - m_minimum));
0263         Q_EMIT timeCodeUpdated();
0264     }
0265 }