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))
}
}*/
}