diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index 2d8a6ef53..deb62f1cf 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -1,1024 +1,1024 @@ 0 4 false true 1 true true false 00:00:05:00 00:00:05:00 00:00:00:01 00:00:03:00 false false false false false 00:00:05:00 00:00:01:00 true - - 0 + + 16 2 2 false false false false 1000 2000 800 0 0 true false false false 140 1 25 false true true true false false true false 0 1 true true true false sdl2_audio 0 sdl2_audio 0 #535353 100 true 1 false 0 1 2 0 /tmp/ false true $HOME true default: 100 2 48000 0 0 /dev/video0 2 default 0 true false 0 0 0 false 0 0 1280 720 15.0 true false false 0 0 capture false 3 false true 0 true 0 25 true false false false true true true false false false false 0x15 0x05 0 0 false 0x07 true true false false true #000000 true 320 240 true false false false true 5 3 false false false 10 0 false false true false false true true true 0 onefield nearest volume,lift_gamma_gain,qtblend wipe,qtblend 0 false false true false 2 3 #ff0000 0 diff --git a/src/main.cpp b/src/main.cpp index 69adb8355..be51fffae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,267 +1,270 @@ /*************************************************************************** * Copyright (C) 2007 by Marco Gittler (g.marco@freenet.de) * * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@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) any later version. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "core.h" #include "dialogs/splash.hpp" #include "logger.hpp" #include #include #include "kxmlgui_version.h" #include #include #ifdef USE_DRMINGW #include #elif defined(KF5_USE_CRASH) #include #endif #include #include #include "definitions.h" #include "kdenlive_debug.h" #include #include #include #include #include #include #include #include #include #include #include //new #include #ifdef Q_OS_WIN extern "C" { // Inform the driver we could make use of the discrete gpu // __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; // __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } #endif int main(int argc, char *argv[]) { #ifdef USE_DRMINGW ExcHndlInit(); #endif // Force QDomDocument to use a deterministic XML attribute order qSetGlobalQHashSeed(0); Logger::init(); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //TODO: is it a good option ? QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) QCoreApplication::setAttribute(Qt::AA_X11InitThreads); #elif defined(Q_OS_WIN) KSharedConfigPtr configWin = KSharedConfig::openConfig("kdenliverc"); KConfigGroup grp1(configWin, "misc"); if (grp1.exists()) { int glMode = grp1.readEntry("opengl_backend", 0); if (glMode > 0) { QCoreApplication::setAttribute((Qt::ApplicationAttribute)glMode, true); } + } else { + // Default to OpenGLES (QtAngle) on first start + QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); } #endif QApplication app(argc, argv); app.setApplicationName(QStringLiteral("kdenlive")); app.setOrganizationDomain(QStringLiteral("kde.org")); app.setWindowIcon(QIcon(QStringLiteral(":/pics/kdenlive.png"))); KLocalizedString::setApplicationDomain("kdenlive"); #ifdef Q_OS_WIN qputenv("KDE_FORK_SLAVES", "1"); QString path = qApp->applicationDirPath() + QLatin1Char(';') + qgetenv("PATH"); qputenv("PATH", path.toUtf8().constData()); const QStringList themes {"/icons/breeze/breeze-icons.rcc", "/icons/breeze-dark/breeze-icons-dark.rcc"}; for(const QString theme : themes ) { const QString themePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, theme); if (!themePath.isEmpty()) { const QString iconSubdir = theme.left(theme.lastIndexOf('/')); if (QResource::registerResource(themePath, iconSubdir)) { if (QFileInfo::exists(QLatin1Char(':') + iconSubdir + QStringLiteral("/index.theme"))) { qDebug() << "Loaded icon theme:" << theme; } else { qWarning() << "No index.theme found in" << theme; QResource::unregisterResource(themePath, iconSubdir); } } else { qWarning() << "Invalid rcc file" << theme; } } } #endif KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp(config, "unmanaged"); if (!grp.exists()) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (env.contains(QStringLiteral("XDG_CURRENT_DESKTOP")) && env.value(QStringLiteral("XDG_CURRENT_DESKTOP")).toLower() == QLatin1String("kde")) { qCDebug(KDENLIVE_LOG) << "KDE Desktop detected, using system icons"; } else { // We are not on a KDE desktop, force breeze icon theme // Check if breeze theme is available QStringList iconThemes = KIconTheme::list(); if (iconThemes.contains(QStringLiteral("breeze"))) { grp.writeEntry("force_breeze", true); grp.writeEntry("use_dark_breeze", true); qCDebug(KDENLIVE_LOG) << "Non KDE Desktop detected, forcing Breeze icon theme"; } } // Set breeze dark as default on first opening KConfigGroup cg(config, "UiSettings"); cg.writeEntry("ColorScheme", "Breeze Dark"); } // Init DBus services KDBusService programDBusService; bool forceBreeze = grp.readEntry("force_breeze", QVariant(false)).toBool(); if (forceBreeze) { bool darkBreeze = grp.readEntry("use_dark_breeze", QVariant(false)).toBool(); QIcon::setThemeName(darkBreeze ? QStringLiteral("breeze-dark") : QStringLiteral("breeze")); } // Create KAboutData KAboutData aboutData(QByteArray("kdenlive"), i18n("Kdenlive"), KDENLIVE_VERSION, i18n("An open source video editor."), KAboutLicense::GPL, i18n("Copyright © 2007–2019 Kdenlive authors"), i18n("Please report bugs to https://bugs.kde.org"), QStringLiteral("https://kdenlive.org")); aboutData.addAuthor(i18n("Jean-Baptiste Mardelle"), i18n("MLT and KDE SC 4 / KF5 port, main developer and maintainer"), QStringLiteral("jb@kdenlive.org")); aboutData.addAuthor(i18n("Nicolas Carion"), i18n("Code re-architecture & timeline rewrite"), QStringLiteral("french.ebook.lover@gmail.com")); aboutData.addAuthor(i18n("Vincent Pinon"), i18n("KF5 port, Windows cross-build, bugs fixing"), QStringLiteral("vpinon@kde.org")); aboutData.addAuthor(i18n("Laurent Montel"), i18n("Bugs fixing, clean up code, optimization etc."), QStringLiteral("montel@kde.org")); aboutData.addAuthor(i18n("Till Theato"), i18n("Bug fixing, etc."), QStringLiteral("root@ttill.de")); aboutData.addAuthor(i18n("Simon A. Eugster"), i18n("Color scopes, bug fixing, etc."), QStringLiteral("simon.eu@gmail.com")); aboutData.addAuthor(i18n("Marco Gittler"), i18n("MLT transitions and effects, timeline, audio thumbs"), QStringLiteral("g.marco@freenet.de")); aboutData.addAuthor(i18n("Dan Dennedy"), i18n("Bug fixing, etc."), QStringLiteral("dan@dennedy.org")); aboutData.addAuthor(i18n("Alberto Villa"), i18n("Bug fixing, logo, etc."), QStringLiteral("avilla@FreeBSD.org")); aboutData.addAuthor(i18n("Jean-Michel Poure"), i18n("Rendering profiles customization"), QStringLiteral("jm@poure.com")); aboutData.addAuthor(i18n("Ray Lehtiniemi"), i18n("Bug fixing, etc."), QStringLiteral("rayl@mail.com")); aboutData.addAuthor(i18n("Steve Guilford"), i18n("Bug fixing, etc."), QStringLiteral("s.guilford@dbplugins.com")); aboutData.addAuthor(i18n("Jason Wood"), i18n("Original KDE 3 version author (not active anymore)"), QStringLiteral("jasonwood@blueyonder.co.uk")); aboutData.addCredit(i18n("Nara Oliveira and Farid Abdelnour | Estúdio Gunga"), i18n("Kdenlive 16.08 icon")); aboutData.setTranslator(i18n("NAME OF TRANSLATORS"), i18n("EMAIL OF TRANSLATORS")); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.setOtherText( i18n("Using:\nMLT version %1\nFFmpeg libraries", mlt_version_get_string())); aboutData.setDesktopFileName(QStringLiteral("org.kde.kdenlive")); // Register about data KAboutData::setApplicationData(aboutData); // Add rcc stored icons to the search path so that we always find our icons KIconLoader *loader = KIconLoader::global(); loader->reconfigure("kdenlive", QStringList() << QStringLiteral(":/pics")); // Set app stuff from about data app.setApplicationDisplayName(aboutData.displayName()); app.setOrganizationDomain(aboutData.organizationDomain()); app.setApplicationVersion(aboutData.version()); app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); // Create command line parser with options QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.setApplicationDescription(aboutData.shortDescription()); parser.addVersionOption(); parser.addHelpOption(); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("config"), i18n("Set a custom config file name"), QStringLiteral("config"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("mlt-path"), i18n("Set the path for MLT environment"), QStringLiteral("mlt-path"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("mlt-log"), i18n("MLT log level"), QStringLiteral("verbose/debug"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("i"), i18n("Comma separated list of clips to add"), QStringLiteral("clips"))); parser.addPositionalArgument(QStringLiteral("file"), i18n("Document to open")); // Parse command line parser.process(app); aboutData.processCommandLine(&parser); #ifdef USE_DRMINGW ExcHndlInit(); #elif defined(KF5_USE_CRASH) KCrash::initialize(); #endif //auto splash = new Splash(&app); //splash->show(); //qApp->processEvents(); qmlRegisterUncreatableMetaObject(PlaylistState::staticMetaObject, // static meta object "com.enums", // import statement 1, 0, // major and minor version of the import "ClipState", // name in QML "Error: only enums"); qmlRegisterUncreatableMetaObject(ClipType::staticMetaObject, // static meta object "com.enums", // import statement 1, 0, // major and minor version of the import "ProducerType", // name in QML "Error: only enums"); if (parser.value(QStringLiteral("mlt-log")) == QStringLiteral("verbose")) { mlt_log_set_level(MLT_LOG_VERBOSE); } else if (parser.value(QStringLiteral("mlt-log")) == QStringLiteral("debug")) { mlt_log_set_level(MLT_LOG_DEBUG); } QUrl url; if (parser.positionalArguments().count() != 0) { url = QUrl::fromLocalFile(parser.positionalArguments().at(0)); // Make sure we get an absolute URL so that we can autosave correctly QString currentPath = QDir::currentPath(); QUrl startup = QUrl::fromLocalFile(currentPath.endsWith(QDir::separator()) ? currentPath : currentPath + QDir::separator()); url = startup.resolved(url); } Core::build(!parser.value(QStringLiteral("config")).isEmpty(), parser.value(QStringLiteral("mlt-path"))); pCore->initGUI(url); //delete splash; //splash->endSplash(); //qApp->processEvents(); int result = app.exec(); Core::clean(); if (result == EXIT_RESTART || result == EXIT_CLEAN_RESTART) { qCDebug(KDENLIVE_LOG) << "restarting app"; if (result == EXIT_CLEAN_RESTART) { // Delete config file KSharedConfigPtr config = KSharedConfig::openConfig(); if (config->name().contains(QLatin1String("kdenlive"))) { // Make sure we delete our config file QFile f(QStandardPaths::locate(QStandardPaths::ConfigLocation, config->name(), QStandardPaths::LocateFile)); if (f.exists()) { qDebug()<<" = = = =\nGOT Deleted file: "<start(app.applicationFilePath(), progArgs); restart->waitForReadyRead(); restart->waitForFinished(1000); result = EXIT_SUCCESS; } return result; } diff --git a/src/timeline2/view/qml/Clip.qml b/src/timeline2/view/qml/Clip.qml index fd9bf4c53..ba0243a2c 100644 --- a/src/timeline2/view/qml/Clip.qml +++ b/src/timeline2/view/qml/Clip.qml @@ -1,961 +1,961 @@ /* * Copyright (c) 2013-2016 Meltytech, LLC * Author: Dan Dennedy * * 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 3 of the License, or * (at your option) any later version. * * 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 . */ import QtQuick 2.11 import QtQuick.Controls 2.4 import Kdenlive.Controls 1.0 import QtQml.Models 2.11 import QtQuick.Window 2.2 import 'Timeline.js' as Logic import com.enums 1.0 Rectangle { id: clipRoot property real timeScale: 1.0 property string clipName: '' property string clipResource: '' property string mltService: '' property string effectNames property int modelStart property real scrollX: 0 property int inPoint: 0 property int outPoint: 0 property int clipDuration: 0 property int maxDuration: 0 property bool isAudio: false property int audioChannels property bool showKeyframes: false property bool isGrabbed: false property bool grouped: false property var markers property var keyframeModel property int clipStatus: 0 property int itemType: 0 property int fadeIn: 0 property int fadeOut: 0 property int binId: 0 property int positionOffset: 0 property var parentTrack property int trackIndex //Index in track repeater property int clipId //Id of the clip in the model property int trackId: -1 // Id of the parent track in the model property int fakeTid: -1 property int fakePosition: 0 property int originalTrackId: -1 property int originalX: x property int originalDuration: clipDuration property int lastValidDuration: clipDuration property int draggedX: x property bool selected: false property bool isLocked: parentTrack && parentTrack.isLocked == true property bool hasAudio property bool canBeAudio property bool canBeVideo property double speed: 1.0 property color borderColor: 'black' property bool forceReloadThumb property bool isComposition: false property bool hideClipViews property var groupTrimData property int scrollStart: scrollView.flickableItem.contentX - clipRoot.modelStart * timeline.scaleFactor width : clipDuration * timeScale; opacity: dragProxyArea.drag.active && dragProxy.draggedItem == clipId ? 0.8 : 1.0 signal trimmingIn(var clip, real newDuration, var mouse, bool shiftTrim, bool controlTrim) signal trimmedIn(var clip, bool shiftTrim, bool controlTrim) signal initGroupTrim(var clip) signal trimmingOut(var clip, real newDuration, var mouse, bool shiftTrim, bool controlTrim) signal trimmedOut(var clip, bool shiftTrim, bool controlTrim) onScrollStartChanged: { clipRoot.hideClipViews = scrollStart > width || scrollStart + scrollView.viewport.width < 0 } onIsGrabbedChanged: { if (clipRoot.isGrabbed) { grabItem() } else { mouseArea.focus = false } } function grabItem() { clipRoot.forceActiveFocus() mouseArea.focus = true } function clearAndMove(offset) { controller.requestClearSelection() controller.requestClipMove(clipRoot.clipId, clipRoot.trackId, clipRoot.modelStart - offset, true, true, true) controller.requestAddToSelection(clipRoot.clipId) } onClipResourceChanged: { if (itemType == ProducerType.Color) { color: Qt.darker(getColor(), 1.5) } } ToolTip { visible: mouseArea.containsMouse && !dragProxyArea.pressed delay: 1000 timeout: 5000 background: Rectangle { color: activePalette.alternateBase border.color: activePalette.light } contentItem: Label { color: activePalette.text font.pointSize: root.fontUnit text: label.text + ' (' + timeline.simplifiedTC(clipRoot.inPoint) + '-' + timeline.simplifiedTC(clipRoot.outPoint) + ')' } } onKeyframeModelChanged: { if (effectRow.keyframecanvas) { console.log('keyframe model changed............') effectRow.keyframecanvas.requestPaint() } } onClipDurationChanged: { width = clipDuration * timeScale; if (parentTrack && parentTrack.isAudio && thumbsLoader.item) { // Duration changed, we may need a different number of repeaters thumbsLoader.item.reload() } } onModelStartChanged: { x = modelStart * timeScale; } onFakePositionChanged: { x = fakePosition * timeScale; } onFakeTidChanged: { if (clipRoot.fakeTid > -1 && parentTrack) { if (clipRoot.parent != dragContainer) { var pos = clipRoot.mapToGlobal(clipRoot.x, clipRoot.y); clipRoot.parent = dragContainer pos = clipRoot.mapFromGlobal(pos.x, pos.y) clipRoot.x = pos.x clipRoot.y = pos.y } clipRoot.y = Logic.getTrackById(clipRoot.fakeTid).y } } onForceReloadThumbChanged: { // TODO: find a way to force reload of clip thumbs if (thumbsLoader.item) { thumbsLoader.item.reload() } } onTimeScaleChanged: { x = modelStart * timeScale; width = clipDuration * timeScale; labelRect.x = scrollX > modelStart * timeScale ? scrollX - modelStart * timeScale : 0 } onScrollXChanged: { labelRect.x = scrollX > modelStart * timeScale ? scrollX - modelStart * timeScale : 0 } border.color: selected ? root.selectionColor : grouped ? root.groupColor : borderColor border.width: isGrabbed ? 8 : 1.5 function updateDrag() { var itemPos = mapToItem(tracksContainerArea, 0, 0, clipRoot.width, clipRoot.height) initDrag(clipRoot, itemPos, clipRoot.clipId, clipRoot.modelStart, clipRoot.trackId, false) } function getColor() { if (clipStatus == ClipState.Disabled) { return 'grey' } if (itemType == ProducerType.Color) { var color = clipResource.substring(clipResource.length - 9) if (color[0] == '#') { return color } return '#' + color.substring(color.length - 8, color.length - 2) } return isAudio? root.audioColor : root.videoColor } /* function reparent(track) { console.log('TrackId: ',trackId) parent = track height = track.height parentTrack = track trackId = parentTrack.trackId console.log('Reparenting clip to Track: ', trackId) //generateWaveform() } */ property bool variableThumbs: (isAudio || itemType == ProducerType.Color || mltService === '') property bool isImage: itemType == ProducerType.Image property string baseThumbPath: variableThumbs ? '' : 'image://thumbnail/' + binId + '/' + documentId + '/' + (isImage ? '#0' : '#') DropArea { //Drop area for clips anchors.fill: clipRoot keys: 'kdenlive/effect' property string dropData property string dropSource property int dropRow: -1 onEntered: { dropData = drag.getDataAsString('kdenlive/effect') dropSource = drag.getDataAsString('kdenlive/effectsource') } onDropped: { console.log("Add effect: ", dropData) if (dropSource == '') { // drop from effects list controller.addClipEffect(clipRoot.clipId, dropData); } else { controller.copyClipEffect(clipRoot.clipId, dropSource); } dropSource = '' dropRow = -1 drag.acceptProposedAction } } MouseArea { id: mouseArea enabled: root.activeTool === 0 anchors.fill: clipRoot acceptedButtons: Qt.RightButton hoverEnabled: root.activeTool === 0 cursorShape: (trimInMouseArea.drag.active || trimOutMouseArea.drag.active)? Qt.SizeHorCursor : dragProxyArea.cursorShape onPressed: { root.autoScrolling = false if (mouse.button == Qt.RightButton) { if (timeline.selection.indexOf(clipRoot.clipId) == -1) { controller.requestAddToSelection(clipRoot.clipId, true) } clipMenu.clipId = clipRoot.clipId clipMenu.clipStatus = clipRoot.clipStatus clipMenu.clipFrame = Math.round(mouse.x / timeline.scaleFactor) clipMenu.grouped = clipRoot.grouped clipMenu.trackId = clipRoot.trackId clipMenu.canBeAudio = clipRoot.canBeAudio clipMenu.canBeVideo = clipRoot.canBeVideo clipMenu.popup() } } Keys.onShortcutOverride: event.accepted = clipRoot.isGrabbed && (event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Up || event.key === Qt.Key_Down || event.key === Qt.Key_Escape) Keys.onLeftPressed: { var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1 controller.requestClipMove(clipRoot.clipId, clipRoot.trackId, clipRoot.modelStart - offset, true, true, true); } Keys.onRightPressed: { var offset = event.modifiers === Qt.ShiftModifier ? timeline.fps() : 1 controller.requestClipMove(clipRoot.clipId, clipRoot.trackId, clipRoot.modelStart + offset, true, true, true); } Keys.onUpPressed: { controller.requestClipMove(clipRoot.clipId, controller.getNextTrackId(clipRoot.trackId), clipRoot.modelStart, true, true, true); } Keys.onDownPressed: { controller.requestClipMove(clipRoot.clipId, controller.getPreviousTrackId(clipRoot.trackId), clipRoot.modelStart, true, true, true); } Keys.onEscapePressed: { timeline.grabCurrent() //focus = false } onPositionChanged: { var mapped = parentTrack.mapFromItem(clipRoot, mouse.x, mouse.y).x root.mousePosChanged(Math.round(mapped / timeline.scaleFactor)) } onEntered: { var itemPos = mapToItem(tracksContainerArea, 0, 0, width, height) initDrag(clipRoot, itemPos, clipRoot.clipId, clipRoot.modelStart, clipRoot.trackId, false) } onExited: { endDrag() } onWheel: zoomByWheel(wheel) Item { // Thumbs container anchors.fill: parent anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.topMargin: clipRoot.border.width anchors.bottomMargin: clipRoot.border.width clip: true Loader { id: thumbsLoader asynchronous: true visible: status == Loader.Ready anchors.fill: parent source: clipRoot.hideClipViews ? "" : parentTrack.isAudio ? (timeline.showAudioThumbnails ? "ClipAudioThumbs.qml" : "") : itemType == ProducerType.Color ? "" : timeline.showThumbnails ? "ClipThumbs.qml" : "" } } Item { // Clipping container id: container anchors.fill: parent anchors.margins: 1.5 clip: true Rectangle { // text background id: labelRect color: clipRoot.selected ? 'darkred' : '#66000000' width: label.width + 2 height: label.height visible: clipRoot.width > width / 2 Text { id: label text: clipName + (clipRoot.speed != 1.0 ? ' [' + Math.round(clipRoot.speed*100) + '%]': '') font.pointSize: root.fontUnit anchors { top: labelRect.top left: labelRect.left topMargin: 1 leftMargin: 1 } color: 'white' style: Text.Outline styleColor: 'black' } } Rectangle { // Offset info id: offsetRect color: 'darkgreen' width: offsetLabel.width + radius height: offsetLabel.height radius: height/3 x: labelRect.width + 4 visible: labelRect.visible && positionOffset != 0 MouseArea { id: offsetArea hoverEnabled: true cursorShape: Qt.PointingHandCursor anchors.fill: parent onClicked: { clearAndMove(positionOffset) } ToolTip { visible: offsetArea.containsMouse delay: 1000 timeout: 5000 background: Rectangle { color: activePalette.alternateBase border.color: activePalette.light } contentItem: Label { color: activePalette.text font.pointSize: root.fontUnit text: positionOffset < 0 ? i18n("Offset: -%1", timeline.simplifiedTC(-positionOffset)) : i18n("Offset: %1", timeline.simplifiedTC(positionOffset)) } } Text { id: offsetLabel text: positionOffset font.pointSize: root.fontUnit anchors { horizontalCenter: parent.horizontalCenter topMargin: 1 leftMargin: 1 } color: 'white' style: Text.Outline styleColor: 'black' } } } Rectangle { // effects id: effectsRect color: '#555555' width: effectLabel.width + 2 height: effectLabel.height x: labelRect.x anchors.top: labelRect.bottom visible: labelRect.visible && clipRoot.effectNames != '' Text { id: effectLabel text: clipRoot.effectNames font.pointSize: root.fontUnit anchors { top: effectsRect.top left: effectsRect.left topMargin: 1 leftMargin: 1 // + ((isAudio || !settings.timelineShowThumbnails) ? 0 : inThumbnail.width) + 1 } color: 'white' //style: Text.Outline styleColor: 'black' } } Repeater { model: markers delegate: Item { anchors.fill: parent Rectangle { id: markerBase width: 1 height: parent.height x: clipRoot.speed < 0 ? clipRoot.clipDuration * timeScale + (Math.round(model.frame / clipRoot.speed) - (clipRoot.maxDuration - clipRoot.outPoint)) * timeScale : (Math.round(model.frame / clipRoot.speed) - clipRoot.inPoint) * timeScale; color: model.color } Rectangle { visible: mlabel.visible opacity: 0.7 x: markerBase.x radius: 2 width: mlabel.width + 4 height: mlabel.height anchors { bottom: parent.verticalCenter } color: model.color MouseArea { z: 10 anchors.fill: parent acceptedButtons: Qt.LeftButton cursorShape: Qt.PointingHandCursor hoverEnabled: true onDoubleClicked: timeline.editMarker(clipRoot.clipId, model.frame) onClicked: proxy.position = (clipRoot.x + markerBase.x) / timeline.scaleFactor } } Text { id: mlabel visible: timeline.showMarkers && parent.width > width * 1.5 text: model.comment font.pointSize: root.fontUnit x: markerBase.x anchors { bottom: parent.verticalCenter topMargin: 2 leftMargin: 2 } color: 'white' } } } KeyframeView { id: effectRow visible: clipRoot.showKeyframes && clipRoot.keyframeModel selected: clipRoot.selected inPoint: clipRoot.inPoint outPoint: clipRoot.outPoint masterObject: clipRoot kfrModel: clipRoot.hideClipViews ? 0 : clipRoot.keyframeModel } } states: [ State { name: 'locked' when: isLocked PropertyChanges { target: clipRoot color: root.lockedColor opacity: 0.8 z: 0 } }, State { name: 'normal' when: clipRoot.selected === false PropertyChanges { target: clipRoot color: Qt.darker(getColor(), 1.5) z: 0 } }, State { name: 'selected' when: clipRoot.selected === true PropertyChanges { target: clipRoot color: getColor() z: 3 } } ] Rectangle { id: compositionIn anchors.left: parent.left anchors.bottom: parent.bottom anchors.bottomMargin: 2 anchors.leftMargin: 4 width: root.baseUnit height: width radius: 2 color: Qt.darker('mediumpurple') border.width: 2 border.color: 'green' opacity: 0 enabled: !clipRoot.isAudio && dragProxy.draggedItem === clipRoot.clipId visible: clipRoot.width > 4 * width MouseArea { id: compInArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onEntered: parent.opacity = 0.7 onExited: { if (!pressed) { parent.opacity = 0 } } onPressed: { timeline.addCompositionToClip('', clipRoot.clipId, 0) } onReleased: { parent.opacity = 0 } ToolTip { visible: compInArea.containsMouse && !dragProxyArea.pressed delay: 1000 timeout: 5000 background: Rectangle { color: activePalette.alternateBase border.color: activePalette.light } contentItem: Label { color: activePalette.text font.pointSize: root.fontUnit text: i18n("Click to add composition") } } } } Rectangle { id: compositionOut anchors.right: parent.right anchors.bottom: parent.bottom anchors.bottomMargin: 2 anchors.rightMargin: 4 width: root.baseUnit height: width radius: 2 color: Qt.darker('mediumpurple') border.width: 2 border.color: 'green' opacity: 0 enabled: !clipRoot.isAudio && dragProxy.draggedItem == clipRoot.clipId visible: clipRoot.width > 4 * width MouseArea { id: compOutArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onEntered: { parent.opacity = 0.7 } onExited: { if (!pressed) { parent.opacity = 0 } } onPressed: { timeline.addCompositionToClip('', clipRoot.clipId, clipRoot.clipDuration - 1) } onReleased: { parent.opacity = 0 } ToolTip { visible: compOutArea.containsMouse && !dragProxyArea.pressed delay: 1000 timeout: 5000 background: Rectangle { color: activePalette.alternateBase border.color: activePalette.light } contentItem: Label { color: activePalette.text font.pointSize: root.fontUnit text: i18n("Click to add composition") } } } } } TimelineTriangle { id: fadeInTriangle fillColor: 'green' width: Math.min(clipRoot.fadeIn * timeScale, clipRoot.width) height: clipRoot.height - clipRoot.border.width * 2 anchors.left: parent.left anchors.top: parent.top anchors.margins: clipRoot.border.width opacity: 0.3 } TimelineTriangle { id: fadeOutCanvas fillColor: 'red' width: Math.min(clipRoot.fadeOut * timeScale, clipRoot.width) height: clipRoot.height - clipRoot.border.width * 2 anchors.right: parent.right anchors.top: parent.top anchors.margins: clipRoot.border.width opacity: 0.3 transform: Scale { xScale: -1; origin.x: fadeOutCanvas.width / 2} } MouseArea { id: trimInMouseArea anchors.left: clipRoot.left anchors.leftMargin: 0 height: parent.height width: root.baseUnit / 2 enabled: !isLocked hoverEnabled: true drag.target: trimInMouseArea drag.axis: Drag.XAxis drag.smoothed: false property bool shiftTrim: false property bool controlTrim: false property bool sizeChanged: false cursorShape: (containsMouse ? Qt.SizeHorCursor : Qt.ClosedHandCursor); onPressed: { root.autoScrolling = false clipRoot.originalX = clipRoot.x clipRoot.originalDuration = clipDuration anchors.left = undefined shiftTrim = mouse.modifiers & Qt.ShiftModifier controlTrim = mouse.modifiers & Qt.ControlModifier if (!shiftTrim && clipRoot.grouped) { clipRoot.initGroupTrim(clipRoot) } trimIn.opacity = 0 } onReleased: { root.autoScrolling = timeline.autoScroll anchors.left = clipRoot.left if (sizeChanged) { clipRoot.trimmedIn(clipRoot, shiftTrim, controlTrim) sizeChanged = false } } onPositionChanged: { if (mouse.buttons === Qt.LeftButton) { var delta = Math.round(x / timeScale) if (delta !== 0) { if (maxDuration > 0 && delta < -inPoint) { delta = -inPoint } var newDuration = clipDuration - delta sizeChanged = true clipRoot.trimmingIn(clipRoot, newDuration, mouse, shiftTrim, controlTrim) } } } onEntered: { if (!pressed) { trimIn.opacity = 0.5 } } onExited: { trimIn.opacity = 0 } Rectangle { id: trimIn anchors.fill: parent anchors.margins: 2 color: isAudio? 'green' : 'lawngreen' opacity: 0 Drag.active: trimInMouseArea.drag.active Drag.proposedAction: Qt.MoveAction visible: trimInMouseArea.pressed || (root.activeTool === 0 && !mouseArea.drag.active && clipRoot.width > 4 * width) ToolTip { visible: trimInMouseArea.containsMouse && !trimInMouseArea.pressed delay: 1000 timeout: 5000 background: Rectangle { color: activePalette.alternateBase border.color: activePalette.light } contentItem: Label { color: activePalette.text font.pointSize: root.fontUnit text: i18n("In:%1\nPosition:%2", timeline.simplifiedTC(clipRoot.inPoint),timeline.simplifiedTC(clipRoot.modelStart)) } } } } MouseArea { id: trimOutMouseArea anchors.right: clipRoot.right height: parent.height width: root.baseUnit / 2 hoverEnabled: true enabled: !isLocked property bool shiftTrim: false property bool controlTrim: false property bool sizeChanged: false cursorShape: (containsMouse ? Qt.SizeHorCursor : Qt.ClosedHandCursor); drag.target: trimOutMouseArea drag.axis: Drag.XAxis drag.smoothed: false onPressed: { root.autoScrolling = false clipRoot.originalDuration = clipDuration anchors.right = undefined shiftTrim = mouse.modifiers & Qt.ShiftModifier controlTrim = mouse.modifiers & Qt.ControlModifier if (!shiftTrim && clipRoot.grouped) { clipRoot.initGroupTrim(clipRoot) } trimOut.opacity = 0 } onReleased: { root.autoScrolling = timeline.autoScroll anchors.right = clipRoot.right if (sizeChanged) { clipRoot.trimmedOut(clipRoot, shiftTrim, controlTrim) sizeChanged = false } } onPositionChanged: { if (mouse.buttons === Qt.LeftButton) { var newDuration = Math.round((x + width) / timeScale) if (maxDuration > 0 && newDuration > maxDuration - inPoint) { newDuration = maxDuration - inPoint } if (newDuration != clipDuration) { sizeChanged = true clipRoot.trimmingOut(clipRoot, newDuration, mouse, shiftTrim, controlTrim) } } } onEntered: { if (!pressed) { trimOut.opacity = 0.5 } } onExited: trimOut.opacity = 0 ToolTip { visible: trimOutMouseArea.containsMouse && !trimOutMouseArea.pressed delay: 1000 timeout: 5000 background: Rectangle { color: activePalette.alternateBase border.color: activePalette.light } contentItem: Label { color: activePalette.text font.pointSize: root.fontUnit text: i18n("Out: ") + timeline.simplifiedTC(clipRoot.outPoint) } } Rectangle { id: trimOut anchors.fill: parent anchors.margins: 2 color: 'red' opacity: 0 Drag.active: trimOutMouseArea.drag.active Drag.proposedAction: Qt.MoveAction visible: trimOutMouseArea.pressed || (root.activeTool === 0 && !mouseArea.drag.active && clipRoot.width > 4 * width) } } MouseArea { id: fadeOutMouseArea anchors.right: fadeOutCanvas.left anchors.rightMargin: -width/2 anchors.top: fadeOutCanvas.top anchors.topMargin: -width / 3 width: root.baseUnit height: width //anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor drag.target: fadeOutMouseArea drag.axis: Drag.XAxis drag.minimumX: - Math.ceil(width / 2) - drag.maximumX: container.width + drag.maximumX: container.width - Math.floor(width / 4) visible : clipRoot.width > 3 * width property int startFadeOut property int lastDuration: -1 onEntered: fadeOutControl.opacity = 0.7 onExited: { if (!pressed) { fadeOutControl.opacity = 0 } } drag.smoothed: false onPressed: { root.autoScrolling = false startFadeOut = clipRoot.fadeOut anchors.right = undefined fadeOutControl.opacity = 1 } onReleased: { fadeOutCanvas.opacity = 0.3 root.autoScrolling = timeline.autoScroll anchors.right = fadeOutCanvas.left if (!fadeOutMouseArea.containsMouse) { fadeOutControl.opacity = 0 } var duration = clipRoot.fadeOut if (duration > 0) { duration += 1 } timeline.adjustFade(clipRoot.clipId, 'fadeout', duration, startFadeOut) bubbleHelp.hide() } onPositionChanged: { if (mouse.buttons === Qt.LeftButton) { - var delta = clipRoot.clipDuration - Math.floor(x / timeScale) + var delta = clipRoot.clipDuration - Math.floor((x + width / 2)/ timeScale) var duration = Math.max(0, delta) duration = Math.min(duration, clipRoot.clipDuration) if (lastDuration != duration) { lastDuration = duration timeline.adjustFade(clipRoot.clipId, 'fadeout', duration, -1) // Show fade duration as time in a "bubble" help. var s = timeline.simplifiedTC(clipRoot.fadeOut + (clipRoot.fadeOut > 0 ? 1 : 0)) bubbleHelp.show(clipRoot.x + x, parentTrack.y + parentTrack.height, s) } } } Rectangle { id: fadeOutControl anchors.fill: parent radius: width / 2 color: '#66FFFFFF' border.width: 2 border.color: 'red' opacity: 0 enabled: !isLocked && !dragProxy.isComposition Drag.active: fadeOutMouseArea.drag.active Rectangle { id: fadeOutMarker anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: parent.width / 3 color: 'red' height: container.height - 1 width: 1 } } } MouseArea { id: fadeInMouseArea anchors.left: fadeInTriangle.right anchors.leftMargin: -width / 2 anchors.top: fadeInTriangle.top anchors.topMargin: -width / 3 width: root.baseUnit height: width hoverEnabled: true cursorShape: Qt.PointingHandCursor drag.target: fadeInMouseArea drag.minimumX: - Math.ceil(width / 2) drag.maximumX: container.width - width / 2 drag.axis: Drag.XAxis drag.smoothed: false property int startFadeIn onEntered: fadeInControl.opacity = 0.7 onExited: { if (!pressed) { fadeInControl.opacity = 0 } } onPressed: { root.autoScrolling = false startFadeIn = clipRoot.fadeIn anchors.left = undefined fadeInControl.opacity = 1 fadeInTriangle.opacity = 0.5 // parentTrack.clipSelected(clipRoot, parentTrack) TODO } onReleased: { root.autoScrolling = timeline.autoScroll fadeInTriangle.opacity = 0.3 if (!fadeInMouseArea.containsMouse) { fadeInControl.opacity = 0 } anchors.left = fadeInTriangle.right console.log('released fade: ', clipRoot.fadeIn) timeline.adjustFade(clipRoot.clipId, 'fadein', clipRoot.fadeIn, startFadeIn) bubbleHelp.hide() } onPositionChanged: { if (mouse.buttons === Qt.LeftButton) { - var delta = Math.round(x / timeScale) + var delta = Math.round((x + width / 2) / timeScale) var duration = Math.max(0, delta) duration = Math.min(duration, clipRoot.clipDuration - 1) if (duration != clipRoot.fadeIn) { timeline.adjustFade(clipRoot.clipId, 'fadein', duration, -1) // Show fade duration as time in a "bubble" help. var s = timeline.simplifiedTC(clipRoot.fadeIn) bubbleHelp.show(clipRoot.x + x, parentTrack.y + parentTrack.height, s) } } } Rectangle { id: fadeInControl anchors.fill: parent radius: width / 2 color: '#FF66FFFF' border.width: 2 border.color: 'green' enabled: !isLocked && !dragProxy.isComposition opacity: 0 visible : clipRoot.width > 3 * width Drag.active: fadeInMouseArea.drag.active Rectangle { id: fadeInMarker anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: parent.width / 3 color: 'green' height: container.height - 1 width: 1 } } } /*MenuItem { id: mergeItem text: i18n("Merge with next clip") onTriggered: timeline.mergeClipWithNext(trackIndex, index, false) } MenuItem { text: i18n("Rebuild Audio Waveform") onTriggered: timeline.remakeAudioLevels(trackIndex, index) }*/ /*onPopupVisibleChanged: { if (visible && application.OS !== 'OS X' && __popupGeometry.height > 0) { // Try to fix menu running off screen. This only works intermittently. menu.__yOffset = Math.min(0, Screen.height - (__popupGeometry.y + __popupGeometry.height + 40)) menu.__xOffset = Math.min(0, Screen.width - (__popupGeometry.x + __popupGeometry.width)) } }*/ }