Add buttons to allow dragging video or audio only component of a clip in bin and monitor

parent fbdbbfe5
......@@ -148,6 +148,9 @@ QVariant AbstractProjectItem::getData(DataType type) const
case ItemTypeRole:
data = QVariant(m_itemType);
break;
case ClipType:
data = clipType();
break;
case JobType:
if (itemType() == ClipItem) {
auto jobIds = pCore->jobManager()->getPendingJobsIds(clipId());
......
......@@ -131,7 +131,8 @@ public:
JobSuccess,
JobStatus,
// Item status (ready or not, missing, waiting, ...)
ClipStatus
ClipStatus,
ClipType
};
enum CLIPSTATUS { StatusReady = 0, StatusMissing, StatusWaiting, StatusDeleting };
......@@ -186,6 +187,7 @@ public:
Note that this function does not account for children, use TreeItem::accumulate if you want to get that information as well.
*/
virtual bool isIncludedInTimeline() { return false; }
virtual ClipType::ProducerType clipType() const = 0;
signals:
void childAdded(AbstractProjectItem *child);
......
This diff is collapsed.
......@@ -78,6 +78,7 @@ protected:
void focusInEvent(QFocusEvent *event) override;
signals:
void focusView();
void updateDragMode(ClipType::ProducerType type);
};
class MyTreeView : public QTreeView
......@@ -100,12 +101,14 @@ protected slots:
private:
QPoint m_startPos;
PlaylistState::ClipState m_dragType;
bool m_editing;
bool performDrag();
bool isEditing() const;
signals:
void focusView();
void updateDragMode(PlaylistState::ClipState type);
};
class SmallJobLabel : public QPushButton
......
......@@ -101,7 +101,7 @@ public:
std::shared_ptr<ProjectClip> clipAt(int ix) override;
/** @brief Returns the clip type as defined in definitions.h */
ClipType::ProducerType clipType() const;
ClipType::ProducerType clipType() const override;
bool selfSoftDelete(Fun &undo, Fun &redo) override;
......
......@@ -153,3 +153,8 @@ bool ProjectFolder::rename(const QString &name, int column)
Q_ASSERT(false);
return false;
}
ClipType::ProducerType ProjectFolder::clipType() const
{
return ClipType::Unknown;
}
......@@ -82,6 +82,7 @@ public:
bool rename(const QString &name, int column) override;
/** @brief Returns a list of all children and sub-children clips. */
QList<std::shared_ptr<ProjectClip>> childClips();
ClipType::ProducerType clipType() const override;
};
#endif
......@@ -77,3 +77,9 @@ bool ProjectFolderUp::rename(const QString &, int)
{
return false;
}
ClipType::ProducerType ProjectFolderUp::clipType() const
{
return ClipType::Unknown;
}
......@@ -73,6 +73,7 @@ public:
QDomElement toXml(QDomDocument &document, bool includeMeta = false) override;
QString getToolTip() const override;
bool rename(const QString &name, int column) override;
ClipType::ProducerType clipType() const override;
private:
Bin *m_bin;
......
......@@ -54,6 +54,7 @@ ProjectItemModel::ProjectItemModel(QObject *parent)
, m_fileWatcher(new FileWatcher())
, m_nextId(1)
, m_blankThumb()
, m_dragType(PlaylistState::Disabled)
{
QPixmap pix(QSize(160, 90));
pix.fill(Qt::lightGray);
......@@ -274,7 +275,21 @@ QMimeData *ProjectItemModel::mimeData(const QModelIndexList &indices) const
std::shared_ptr<AbstractProjectItem> item = getBinItemByIndex(ix);
AbstractProjectItem::PROJECTITEMTYPE type = item->itemType();
if (type == AbstractProjectItem::ClipItem) {
list << item->clipId();
ClipType::ProducerType cType = item->clipType();
QString dragId = item->clipId();
if ((cType == ClipType::AV || cType == ClipType::Playlist)) {
switch (m_dragType) {
case PlaylistState::AudioOnly:
dragId.prepend(QLatin1Char('A'));
break;
case PlaylistState::VideoOnly:
dragId.prepend(QLatin1Char('V'));
break;
default:
break;
}
}
list << dragId;
duration += (std::static_pointer_cast<ProjectClip>(item))->frameDuration();
} else if (type == AbstractProjectItem::SubClipItem) {
QPoint p = item->zone();
......@@ -594,13 +609,17 @@ bool ProjectItemModel::requestAddBinSubClip(QString &id, int in, int out, const
id = QString::number(getFreeClipId());
}
Q_ASSERT(!id.isEmpty() && isIdFree(id));
auto clip = getClipByBinID(parentId);
QString subId = parentId;
if (subId.startsWith(QLatin1Char('A')) || subId.startsWith(QLatin1Char('V'))) {
subId.remove(0, 1);
}
auto clip = getClipByBinID(subId);
Q_ASSERT(clip->itemType() == AbstractProjectItem::ClipItem);
auto tc = pCore->currentDoc()->timecode().getDisplayTimecodeFromFrames(in, KdenliveSettings::frametimecode());
std::shared_ptr<ProjectSubClip> new_clip = ProjectSubClip::construct(id, clip, std::static_pointer_cast<ProjectItemModel>(shared_from_this()), in, out, tc, zoneName);
bool res = addItem(new_clip, parentId, undo, redo);
bool res = addItem(new_clip, subId, undo, redo);
if (res) {
int parentJob = pCore->jobManager()->getBlockingJobId(parentId, AbstractClipJob::LOADJOB);
int parentJob = pCore->jobManager()->getBlockingJobId(subId, AbstractClipJob::LOADJOB);
pCore->jobManager()->startJob<ThumbJob>({id}, parentJob, QString(), 150, -1, true);
}
return res;
......@@ -882,3 +901,8 @@ void ProjectItemModel::updateWatcher(std::shared_ptr<ProjectClip> clipItem)
m_fileWatcher->addFile(clipItem->clipId(), clipItem->clipUrl());
}
}
void ProjectItemModel::setDragType(PlaylistState::ClipState type)
{
m_dragType = type;
}
......@@ -216,6 +216,7 @@ public slots:
/** @brief Check whether a given id is currently used or not*/
bool isIdFree(const QString &id) const;
void setDragType(PlaylistState::ClipState type);
private:
/** @brief Return reference to column specific data */
......@@ -228,8 +229,8 @@ private:
std::unique_ptr<FileWatcher> m_fileWatcher;
int m_nextId;
QIcon m_blankThumb;
PlaylistState::ClipState m_dragType;
signals:
// thumbs of the given clip were modified, request update of the monitor if need be
void refreshAudioThumbs(const QString &id);
......
......@@ -162,3 +162,8 @@ std::shared_ptr<ProjectClip> ProjectSubClip::getMasterClip() const
{
return m_masterClip;
}
ClipType::ProducerType ProjectSubClip::clipType() const
{
return m_masterClip->clipType();
}
......@@ -81,6 +81,7 @@ public:
/** @brief returns a pointer to the parent clip */
std::shared_ptr<ProjectClip> getMasterClip() const;
ClipType::ProducerType clipType() const override;
private:
std::shared_ptr<ProjectClip> m_masterClip;
......
......@@ -590,7 +590,7 @@ void GLWidget::wheelEvent(QWheelEvent *event)
slotZoom(event->delta() > 0);
return;
}
emit mouseSeek(-event->delta(), (uint)event->modifiers());
emit mouseSeek(event->delta(), (uint)event->modifiers());
event->accept();
}
......
......@@ -813,6 +813,13 @@ void Monitor::slotStartDrag()
auto *drag = new QDrag(this);
auto *mimeData = new QMimeData;
// Get drag state
QQuickItem *root = m_glMonitor->rootObject();
int dragType = 0;
if (root) {
dragType = root->property("dragType").toInt();
root->setProperty("dragType", 0);
}
QByteArray prodData;
QPoint p = m_glMonitor->getControllerProxy()->zone();
if (p.x() == -1 || p.y() == -1) {
......@@ -824,6 +831,18 @@ void Monitor::slotStartDrag()
list.append(QString::number(p.y() - 1));
prodData.append(list.join(QLatin1Char('/')).toUtf8());
}
switch (dragType) {
case 1:
// Audio only drag
prodData.prepend('A');
break;
case 2:
// Audio only drag
prodData.prepend('V');
break;
default:
break;
}
mimeData->setData(QStringLiteral("kdenlive/producerslist"), prodData);
drag->setMimeData(mimeData);
/*QPixmap pix = m_currentClip->thumbnail();
......
......@@ -34,6 +34,7 @@ Item {
property int overlayType: controller.overlayType
property color overlayColor: 'cyan'
property bool isClipMonitor: true
property int dragType: 0
FontMetrics {
id: fontMetrics
......@@ -205,6 +206,46 @@ Item {
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
......
......@@ -434,8 +434,7 @@ bool TimelineFunctions::switchEnableState(std::shared_ptr<TimelineItemModel> tim
PlaylistState::ClipState state = PlaylistState::Disabled;
bool disable = true;
if (oldState == PlaylistState::Disabled) {
bool audio = timeline->getTrackById_const(timeline->getClipTrackId(clipId))->isAudioTrack();
state = audio ? PlaylistState::AudioOnly : PlaylistState::VideoOnly;
state = timeline->getTrackById_const(timeline->getClipTrackId(clipId))->trackType();
disable = false;
}
Fun undo = []() { return true; };
......
......@@ -422,9 +422,7 @@ bool TimelineModel::fakeClipMove(int clipId, int trackId, int position, bool upd
bool trackChanged = false;
if (trackId > -1) {
if (trackId != m_allClips[clipId]->getFakeTrackId()) {
PlaylistState::ClipState clipState = m_allClips[clipId]->clipState();
bool audioTrack = getTrackById_const(trackId)->isAudioTrack();
if ((audioTrack && clipState == PlaylistState::AudioOnly) || (!audioTrack && clipState == PlaylistState::VideoOnly)) {
if (getTrackById_const(trackId)->trackType() == m_allClips[clipId]->clipState()) {
m_allClips[clipId]->setFakeTrackId(trackId);
trackChanged = true;
}
......@@ -449,6 +447,10 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
return false;
}
Q_ASSERT(isClip(clipId));
if (getTrackById_const(trackId)->trackType() != m_allClips[clipId]->clipState()) {
// Move not allowed (audio / video mismatch)
return false;
}
std::function<bool(void)> local_undo = []() { return true; };
std::function<bool(void)> local_redo = []() { return true; };
bool ok = true;
......@@ -858,19 +860,28 @@ bool TimelineModel::requestClipInsertion(const QString &binClipId, int trackId,
bool res = false;
ClipType::ProducerType type = ClipType::Unknown;
QString bid = binClipId.section(QLatin1Char('/'), 0, 0);
// dropType indicates if we want a normal drop (disabled), audio only or video only drop
PlaylistState::ClipState dropType = PlaylistState::Disabled;
if (bid.startsWith(QLatin1Char('A'))) {
dropType = PlaylistState::AudioOnly;
bid = bid.remove(0, 1);
} else if (bid.startsWith(QLatin1Char('V'))) {
dropType = PlaylistState::VideoOnly;
bid = bid.remove(0, 1);
}
if (!pCore->projectItemModel()->hasClip(bid)) {
return false;
}
std::shared_ptr<ProjectClip> master = pCore->projectItemModel()->getClipByBinID(bid);
type = master->clipType();
if (type == ClipType::AV || type == ClipType::Playlist) {
if (dropType == PlaylistState::Disabled && (type == ClipType::AV || type == ClipType::Playlist)) {
if (m_audioTarget >= 0 && m_videoTarget == -1 && useTargets) {
// If audio target is set but no video target, only insert audio
trackId = m_audioTarget;
}
bool audioDrop = getTrackById_const(trackId)->isAudioTrack();
res = requestClipCreation(binClipId, id, audioDrop ? PlaylistState::AudioOnly : PlaylistState::VideoOnly, local_undo, local_redo);
res = requestClipCreation(binClipId, id, getTrackById_const(trackId)->trackType(), local_undo, local_redo);
res = res && requestClipMove(id, trackId, position, refreshView, logUndo, local_undo, local_redo);
if (m_videoTarget >= 0 && m_audioTarget == -1) {
// No audio target defined, only extract video
......@@ -925,7 +936,17 @@ bool TimelineModel::requestClipInsertion(const QString &binClipId, int trackId,
}
} else {
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(bid);
res = requestClipCreation(binClipId, id, binClip->defaultState(), local_undo, local_redo);
if (dropType == PlaylistState::Disabled) {
dropType = getTrackById_const(trackId)->trackType();
} else if (dropType != getTrackById_const(trackId)->trackType()) {
qDebug()<<"// INCORRECT DRAG, ABORTING";
return false;
}
QString normalisedBinId = binClipId;
if (normalisedBinId.startsWith(QLatin1Char('A')) || normalisedBinId.startsWith(QLatin1Char('V'))) {
normalisedBinId.remove(0, 1);
}
res = requestClipCreation(normalisedBinId, id, dropType, local_undo, local_redo);
res = res && requestClipMove(id, trackId, position, refreshView, logUndo, local_undo, local_redo);
}
if (!res) {
......
......@@ -1088,6 +1088,11 @@ bool TrackModel::isAudioTrack() const
return m_track->get_int("kdenlive:audio_track") == 1;
}
PlaylistState::ClipState TrackModel::trackType() const
{
return (m_track->get_int("kdenlive:audio_track") == 1 ? PlaylistState::AudioOnly : PlaylistState::VideoOnly);
}
bool TrackModel::isHidden() const
{
return m_track->get_int("hide") & 1;
......
......@@ -22,6 +22,7 @@
#ifndef TRACKMODEL_H
#define TRACKMODEL_H
#include "definitions.h"
#include "undohelper.hpp"
#include <QReadWriteLock>
#include <QSharedPointer>
......@@ -87,6 +88,9 @@ public:
/* @brief Returns true if track is an audio track
*/
bool isAudioTrack() const;
/* @brief Returns the track type (audio / video)
*/
PlaylistState::ClipState trackType() const;
/* @brief Returns true if track is disabled
*/
bool isHidden() const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment