diff --git a/src/monitor/qmlmanager.cpp b/src/monitor/qmlmanager.cpp index ec6567bab..5abfae071 100644 --- a/src/monitor/qmlmanager.cpp +++ b/src/monitor/qmlmanager.cpp @@ -1,156 +1,160 @@ /*************************************************************************** * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * * This file is part of Kdenlive. See www.kdenlive.org. * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #include "qmlmanager.h" #include "qml/qmlaudiothumb.h" #include +#include +#include QmlManager::QmlManager(QQuickView *view) : QObject(view) , m_view(view) , m_sceneType(MonitorSceneNone) { } void QmlManager::enableAudioThumbs(bool enable) { auto *audioThumbDisplay = m_view->rootObject()->findChild(QStringLiteral("audiothumb")); if (audioThumbDisplay) { audioThumbDisplay->setProperty("stateVisible", enable); } } MonitorSceneType QmlManager::sceneType() const { return m_sceneType; } void QmlManager::setProperty(const QString &name, const QVariant &value) { m_view->rootObject()->setProperty(name.toUtf8().constData(), value); } void QmlManager::setScene(Kdenlive::MonitorId id, MonitorSceneType type, QSize profile, double profileStretch, QRect displayRect, double zoom, int duration) { if (type == m_sceneType) { // Scene type already active return; } if (id == Kdenlive::DvdMonitor) { return; } m_sceneType = type; - QQuickItem *root; + QQuickItem *root = nullptr; switch (type) { case MonitorSceneGeometry: m_view->setSource(QUrl(QStringLiteral("qrc:/qml/kdenlivemonitoreffectscene.qml"))); root = m_view->rootObject(); QObject::connect(root, SIGNAL(effectChanged()), this, SLOT(effectRectChanged()), Qt::UniqueConnection); QObject::connect(root, SIGNAL(centersChanged()), this, SLOT(effectPolygonChanged()), Qt::UniqueConnection); root->setProperty("profile", QPoint(profile.width(), profile.height())); root->setProperty("framesize", QRect(0, 0, profile.width(), profile.height())); root->setProperty("scalex", (double)displayRect.width() / profile.width() * zoom); root->setProperty("scaley", (double)displayRect.width() / profileStretch / profile.width() * zoom); root->setProperty("center", displayRect.center()); break; case MonitorSceneCorners: qDebug()<<"/// LOADING CORNERS SCENE\n\n+++++++++++++++++++++++++\n------------------\n+++++++++++++++++"; m_view->setSource(QUrl(QStringLiteral("qrc:/qml/kdenlivemonitorcornerscene.qml"))); root = m_view->rootObject(); QObject::connect(root, SIGNAL(effectPolygonChanged()), this, SLOT(effectPolygonChanged()), Qt::UniqueConnection); root->setProperty("profile", QPoint(profile.width(), profile.height())); root->setProperty("framesize", QRect(0, 0, profile.width(), profile.height())); root->setProperty("scalex", (double)displayRect.width() / profile.width() * zoom); root->setProperty("scaley", (double)displayRect.width() / profileStretch / profile.width() * zoom); root->setProperty("stretch", profileStretch); root->setProperty("center", displayRect.center()); break; case MonitorSceneRoto: // TODO m_view->setSource(QUrl(QStringLiteral("qrc:/qml/kdenlivemonitorrotoscene.qml"))); root = m_view->rootObject(); QObject::connect(root, SIGNAL(effectPolygonChanged()), this, SLOT(effectRotoChanged()), Qt::UniqueConnection); root->setProperty("profile", QPoint(profile.width(), profile.height())); root->setProperty("framesize", QRect(0, 0, profile.width(), profile.height())); root->setProperty("scalex", (double)displayRect.width() / profile.width() * zoom); root->setProperty("scaley", (double)displayRect.width() / profileStretch / profile.width() * zoom); root->setProperty("stretch", profileStretch); root->setProperty("center", displayRect.center()); break; case MonitorSceneSplit: m_view->setSource(QUrl(QStringLiteral("qrc:/qml/kdenlivemonitorsplit.qml"))); root = m_view->rootObject(); break; case MonitorSceneRipple: m_view->setSource(QUrl(QStringLiteral("qrc:/qml/kdenlivemonitorripple.qml"))); root = m_view->rootObject(); break; default: m_view->setSource( QUrl(id == Kdenlive::ClipMonitor ? QStringLiteral("qrc:/qml/kdenliveclipmonitor.qml") : QStringLiteral("qrc:/qml/kdenlivemonitor.qml"))); root = m_view->rootObject(); root->setProperty("profile", QPoint(profile.width(), profile.height())); root->setProperty("scalex", (double)displayRect.width() / profile.width() * zoom); root->setProperty("scaley", (double)displayRect.width() / profileStretch / profile.width() * zoom); break; } - if (duration > 0) { + if (root && duration > 0) { root->setProperty("duration", duration); } + const QFont ft = QFontDatabase::systemFont(QFontDatabase::FixedFont); + m_view->rootContext()->setContextProperty("fixedFont", ft); } void QmlManager::effectRectChanged() { if (!m_view->rootObject()) { return; } const QRect rect = m_view->rootObject()->property("framesize").toRect(); emit effectChanged(rect); } void QmlManager::effectPolygonChanged() { if (!m_view->rootObject()) { return; } QVariantList points = m_view->rootObject()->property("centerPoints").toList(); qDebug()<<"// GOT NEW POLYGON FROM QML: "<rootObject()) { return; } QVariantList points = m_view->rootObject()->property("centerPoints").toList(); QVariantList controlPoints = m_view->rootObject()->property("centerPointsTypes").toList(); // rotoscoping effect needs a list of QVariantList mix; mix.reserve(points.count()); for (int i = 0; i < points.count(); i++) { mix << controlPoints.at(2 * i); mix << points.at(i); mix << controlPoints.at(2 * i + 1); } emit effectPointsChanged(mix); } diff --git a/src/monitor/view/kdenliveclipmonitor.qml b/src/monitor/view/kdenliveclipmonitor.qml index 85070ddbe..554cd38a7 100644 --- a/src/monitor/view/kdenliveclipmonitor.qml +++ b/src/monitor/view/kdenliveclipmonitor.qml @@ -1,263 +1,263 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Window 2.2 import Kdenlive.Controls 1.0 import QtQuick 2.6 import AudioThumb 1.0 Item { id: root objectName: "root" SystemPalette { id: activePalette } // default size, but scalable by user height: 300; width: 400 property string markerText property point profile property double zoom property double scalex property double scaley property bool dropped property string fps property bool showMarkers property bool showTimecode property bool showFps property bool showSafezone property bool showAudiothumb property bool showToolbar: false property real baseUnit: fontMetrics.font.pixelSize * 0.8 property int duration: 300 property int mouseRulerPos: 0 property double frameSize: 10 property double timeScale: 1 property int overlayType: controller.overlayType property color overlayColor: 'cyan' property bool isClipMonitor: true property int dragType: 0 FontMetrics { id: fontMetrics font.family: "Arial" } signal editCurrentMarker() signal toolBarChanged(bool doAccept) onDurationChanged: { clipMonitorRuler.updateRuler() } onWidthChanged: { clipMonitorRuler.updateRuler() } function updatePalette() { clipMonitorRuler.forceRepaint() } function switchOverlay() { if (controller.overlayType >= 5) { controller.overlayType = 0 } else { controller.overlayType = controller.overlayType + 1; } root.overlayType = controller.overlayType } MouseArea { id: barOverArea hoverEnabled: true acceptedButtons: Qt.NoButton anchors.fill: parent } SceneToolBar { id: sceneToolBar anchors { right: parent.right top: parent.top topMargin: 4 rightMargin: 4 } visible: barOverArea.mouseX >= x - 10 } Item { height: root.height - controller.rulerHeight width: root.width Item { id: frame objectName: "referenceframe" width: root.profile.x * root.scalex height: root.profile.y * root.scaley anchors.centerIn: parent Loader { anchors.fill: parent source: { switch(root.overlayType) { case 0: { return ''; } case 1: { return "OverlayStandard.qml"; } case 2:{ return "OverlayMinimal.qml"; } case 3:{ return "OverlayCenter.qml"; } case 4:{ return "OverlayCenterDiagonal.qml"; } case 5:{ return "OverlayThirds.qml"; } } } } } Item { id: monitorOverlay anchors.fill: parent QmlAudioThumb { id: audioThumb objectName: "audiothumb" property bool stateVisible: true anchors { left: parent.left bottom: parent.bottom } height: parent.height / 6 //font.pixelSize * 3 width: parent.width visible: root.showAudiothumb MouseArea { id: mouseOverArea hoverEnabled: true onExited: audioThumb.stateVisible = false onEntered: audioThumb.stateVisible = true acceptedButtons: Qt.NoButton anchors.fill: parent } states: [ State { when: audioThumb.stateVisible; PropertyChanges { target: audioThumb; opacity: 1.0 } }, State { when: !audioThumb.stateVisible; PropertyChanges { target: audioThumb; opacity: 0.0 } } ] transitions: [ Transition { NumberAnimation { property: "opacity"; duration: 500} } ] } Text { id: timecode + font: fixedFont objectName: "timecode" color: "white" style: Text.Outline; styleColor: "black" text: controller.toTimecode(controller.position) - font.pixelSize: root.baseUnit visible: root.showTimecode anchors { right: parent.right bottom: parent.bottom rightMargin: 4 } } Text { id: fpsdropped + font: fixedFont objectName: "fpsdropped" color: root.dropped ? "red" : "white" style: Text.Outline; styleColor: "black" text: root.fps + "fps" visible: root.showFps - font.pixelSize: root.baseUnit anchors { right: timecode.visible ? timecode.left : parent.right bottom: parent.bottom rightMargin: 10 } } TextField { id: marker + font: fixedFont objectName: "markertext" activeFocusOnPress: true onEditingFinished: { root.markerText = marker.displayText marker.focus = false root.editCurrentMarker() } anchors { left: parent.left bottom: parent.bottom } visible: root.showMarkers && text != "" text: controller.markerComment maximumLength: 20 style: TextFieldStyle { textColor: "white" background: Rectangle { color: controller.position == controller.zoneIn ? "#9900ff00" : controller.position == controller.zoneOut ? "#99ff0000" : "#990000ff" width: marker.width } } - font.pixelSize: root.baseUnit } } MouseArea { id: dragOverArea hoverEnabled: true acceptedButtons: Qt.LeftButton x: 0 width: 2 * audioDragButton.width height: 2.5 * audioDragButton.height y: parent.height - height propagateComposedEvents: true onPressed: { // First found child is the Column var clickedChild = childAt(mouseX,mouseY).childAt(mouseX,mouseY) if (clickedChild == audioDragButton) { dragType = 1 } else if (clickedChild == videoDragButton) { dragType = 2 } else { dragType = 0 } mouse.accepted = false } Column { ToolButton { id: audioDragButton iconName: "audio-volume-medium" tooltip: "Audio only drag" x: 10 enabled: false visible: dragOverArea.containsMouse } ToolButton { id: videoDragButton iconName: "kdenlive-show-video" tooltip: "Video only drag" x: 10 enabled: false visible: dragOverArea.containsMouse } } } } MonitorRuler { id: clipMonitorRuler anchors { left: root.left right: root.right bottom: root.bottom } height: controller.rulerHeight } } diff --git a/src/monitor/view/kdenlivemonitor.qml b/src/monitor/view/kdenlivemonitor.qml index 4680ce89b..c382ee552 100644 --- a/src/monitor/view/kdenlivemonitor.qml +++ b/src/monitor/view/kdenlivemonitor.qml @@ -1,188 +1,188 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Window 2.2 import Kdenlive.Controls 1.0 import QtQuick 2.4 import AudioThumb 1.0 Item { id: root objectName: "root" SystemPalette { id: activePalette } // default size, but scalable by user height: 300; width: 400 property string markerText property point profile property double zoom property double scalex property double scaley property bool dropped property string fps property bool showMarkers property bool showTimecode property bool showFps property bool showSafezone property bool showAudiothumb property real baseUnit: fontMetrics.font.pixelSize * 0.8 property int duration: 300 property int mouseRulerPos: 0 property double frameSize: 10 property double timeScale: 1 property int overlayType: controller.overlayType property color overlayColor: 'cyan' property bool isClipMonitor: false FontMetrics { id: fontMetrics font.family: "Arial" } signal editCurrentMarker() signal toolBarChanged(bool doAccept) onDurationChanged: { clipMonitorRuler.updateRuler() } onWidthChanged: { clipMonitorRuler.updateRuler() } function updatePalette() { clipMonitorRuler.forceRepaint() } function switchOverlay() { if (controller.overlayType >= 5) { controller.overlayType = 0 } else { controller.overlayType = controller.overlayType + 1; } root.overlayType = controller.overlayType } MouseArea { id: barOverArea hoverEnabled: true acceptedButtons: Qt.NoButton anchors.fill: parent } SceneToolBar { id: sceneToolBar anchors { right: parent.right top: parent.top topMargin: 4 rightMargin: 4 } visible: barOverArea.mouseX >= x - 10 } Item { height: root.height - controller.rulerHeight width: root.width Item { id: frame objectName: "referenceframe" width: root.profile.x * root.scalex height: root.profile.y * root.scaley anchors.centerIn: parent Loader { anchors.fill: parent source: { switch(root.overlayType) { case 0: { return ''; } case 1: { return "OverlayStandard.qml"; } case 2:{ return "OverlayMinimal.qml"; } case 3:{ return "OverlayCenter.qml"; } case 4:{ return "OverlayCenterDiagonal.qml"; } case 5:{ return "OverlayThirds.qml"; } } } } } Item { id: monitorOverlay anchors.fill: parent Text { id: timecode + font: fixedFont objectName: "timecode" color: "white" style: Text.Outline; styleColor: "black" text: controller.toTimecode(controller.position) - font.pixelSize: root.baseUnit visible: root.showTimecode anchors { right: parent.right bottom: parent.bottom rightMargin: 4 } } Text { id: fpsdropped + font: fixedFont objectName: "fpsdropped" color: root.dropped ? "red" : "white" style: Text.Outline; styleColor: "black" text: root.fps + "fps" visible: root.showFps - font.pixelSize: root.baseUnit anchors { right: timecode.visible ? timecode.left : parent.right bottom: parent.bottom rightMargin: 10 } } TextField { id: marker + font: fixedFont objectName: "markertext" activeFocusOnPress: true onEditingFinished: { root.markerText = marker.displayText marker.focus = false root.editCurrentMarker() } anchors { left: parent.left bottom: parent.bottom } visible: root.showMarkers && text != "" text: controller.markerComment maximumLength: 20 style: TextFieldStyle { textColor: "white" background: Rectangle { color: controller.position == controller.zoneIn ? "#9900ff00" : controller.position == controller.zoneOut ? "#99ff0000" : "#990000ff" width: marker.width } } - font.pixelSize: root.baseUnit } } } MonitorRuler { id: clipMonitorRuler anchors { left: root.left right: root.right bottom: root.bottom } height: controller.rulerHeight } } diff --git a/src/timecodedisplay.cpp b/src/timecodedisplay.cpp index 91ab571c4..2ba5ecf4d 100644 --- a/src/timecodedisplay.cpp +++ b/src/timecodedisplay.cpp @@ -1,241 +1,241 @@ /* This file is part of the KDE project Copyright (c) 2010 Jean-Baptiste Mardelle This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "timecodedisplay.h" #include "kdenlivesettings.h" #include #include #include #include #include MyValidator::MyValidator(QObject *parent) : QValidator(parent) { } void MyValidator::fixup(QString &str) const { str.replace(QLatin1Char(' '), QLatin1Char('0')); } QValidator::State MyValidator::validate(QString &str, int &) const { if (str.contains(QLatin1Char(' '))) { fixup(str); } return QValidator::Acceptable; } TimecodeDisplay::TimecodeDisplay(const Timecode &t, QWidget *parent) : QAbstractSpinBox(parent) , m_timecode(t) , m_frametimecode(false) , m_minimum(0) , m_maximum(-1) , m_value(0) { - QFont ft = QFontDatabase::systemFont(QFontDatabase::FixedFont); + const QFont ft = QFontDatabase::systemFont(QFontDatabase::FixedFont); lineEdit()->setFont(ft); setFont(ft); lineEdit()->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QFontMetrics fm(ft); setFrame(false); QPalette palette; palette.setColor(QPalette::Base, Qt::transparent); // palette.window().color()); setPalette(palette); setTimeCodeFormat(KdenliveSettings::frametimecode(), true); setValue(m_minimum); setMinimumWidth(fm.width(QStringLiteral("88:88:88:88")) + contentsMargins().right() + contentsMargins().left() + frameSize().width() - lineEdit()->contentsRect().width() + (int)QStyle::PM_SpinBoxFrameWidth + 6); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum); setAccelerated(true); connect(lineEdit(), &QLineEdit::editingFinished, this, &TimecodeDisplay::slotEditingFinished); } // virtual protected QAbstractSpinBox::StepEnabled TimecodeDisplay::stepEnabled() const { QAbstractSpinBox::StepEnabled result = QAbstractSpinBox::StepNone; if (m_value > m_minimum) { result |= QAbstractSpinBox::StepDownEnabled; } if (m_maximum == -1 || m_value < m_maximum) { result |= QAbstractSpinBox::StepUpEnabled; } return result; } // virtual void TimecodeDisplay::stepBy(int steps) { int val = m_value + steps; setValue(val); } void TimecodeDisplay::setTimeCodeFormat(bool frametimecode, bool init) { if (!init && m_frametimecode == frametimecode) { return; } m_frametimecode = frametimecode; lineEdit()->clear(); if (m_frametimecode) { auto *valid = new QIntValidator(lineEdit()); valid->setBottom(0); lineEdit()->setValidator(valid); lineEdit()->setInputMask(QString()); } else { lineEdit()->setInputMask(m_timecode.mask()); auto *valid = new MyValidator(lineEdit()); lineEdit()->setValidator(valid); } setValue(m_value); } void TimecodeDisplay::slotUpdateTimeCodeFormat() { setTimeCodeFormat(KdenliveSettings::frametimecode()); } void TimecodeDisplay::updateTimeCode(const Timecode &t) { m_timecode = t; setTimeCodeFormat(KdenliveSettings::frametimecode()); } void TimecodeDisplay::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { e->setAccepted(true); clearFocus(); } else { QAbstractSpinBox::keyPressEvent(e); } } void TimecodeDisplay::mouseReleaseEvent(QMouseEvent *e) { QAbstractSpinBox::mouseReleaseEvent(e); if (!lineEdit()->underMouse()) { clearFocus(); } } void TimecodeDisplay::wheelEvent(QWheelEvent *e) { QAbstractSpinBox::wheelEvent(e); clearFocus(); } void TimecodeDisplay::enterEvent(QEvent *e) { QAbstractSpinBox::enterEvent(e); setFrame(true); } void TimecodeDisplay::leaveEvent(QEvent *e) { QAbstractSpinBox::leaveEvent(e); setFrame(false); } int TimecodeDisplay::maximum() const { return m_maximum; } int TimecodeDisplay::minimum() const { return m_minimum; } int TimecodeDisplay::getValue() const { return m_value; } GenTime TimecodeDisplay::gentime() const { return GenTime(m_value, m_timecode.fps()); } Timecode TimecodeDisplay::timecode() const { return m_timecode; } void TimecodeDisplay::setRange(int min, int max) { m_minimum = min; m_maximum = max; } void TimecodeDisplay::setValue(const QString &value) { setValue(m_timecode.getFrameCount(value)); } void TimecodeDisplay::setValue(int value) { if (m_maximum > 0) { value = qBound(m_minimum, value, m_maximum); } else { value = qMax(m_minimum, value); } if (m_frametimecode) { if (value == m_value && !lineEdit()->text().isEmpty()) { return; } m_value = value; lineEdit()->setText(QString::number(value - m_minimum)); } else { if (value == m_value && lineEdit()->text() != QLatin1String(":::")) { return; } m_value = value; QString v = m_timecode.getTimecodeFromFrames(value - m_minimum); lineEdit()->setText(v); } } void TimecodeDisplay::setValue(const GenTime &value) { setValue((int)value.frames(m_timecode.fps())); } void TimecodeDisplay::slotEditingFinished() { lineEdit()->deselect(); if (m_frametimecode) { setValue(lineEdit()->text().toInt() + m_minimum); } else { setValue(m_timecode.getFrameCount(lineEdit()->text()) + m_minimum); } emit timeCodeEditingFinished(m_value); } const QString TimecodeDisplay::displayText() const { return lineEdit()->displayText(); }