footageviewer: allows users to drag video or audio only
Updates drag mime data to include a variable determining which streams are enabled and which ones aren't (a binary qint64 where the 0s are disabled and the 1s are enabled) rather than relying solely on the stream->enabled values which can't be modified as part of the drag process.
This commit is contained in:
@@ -272,6 +272,22 @@ QString Footage::rate()
|
||||
return QString();
|
||||
}
|
||||
|
||||
quint64 Footage::get_enabled_stream_flags() const
|
||||
{
|
||||
quint64 enabled_streams = 0;
|
||||
quint64 stream_enabler = 1;
|
||||
|
||||
foreach (StreamPtr s, streams_) {
|
||||
if (s->enabled()) {
|
||||
enabled_streams |= stream_enabler;
|
||||
}
|
||||
|
||||
stream_enabler <<= 1;
|
||||
}
|
||||
|
||||
return enabled_streams;
|
||||
}
|
||||
|
||||
void Footage::ClearStreams()
|
||||
{
|
||||
if (streams_.empty()) {
|
||||
|
||||
@@ -203,6 +203,8 @@ public:
|
||||
|
||||
virtual QString rate() override;
|
||||
|
||||
quint64 get_enabled_stream_flags() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Internal function to delete all Stream children and empty the array
|
||||
|
||||
@@ -272,7 +272,7 @@ QMimeData *ProjectViewModel::mimeData(const QModelIndexList &indexes) const
|
||||
// Check if we've dragged this item before
|
||||
if (!dragged_items.contains(index.internalPointer())) {
|
||||
// If not, add it to the stream (and also keep track of it in the vector)
|
||||
stream << index.row() << reinterpret_cast<quintptr>(index.internalPointer());
|
||||
stream << static_cast<Footage*>(index.internalPointer())->get_enabled_stream_flags() << index.row() << reinterpret_cast<quintptr>(index.internalPointer());
|
||||
dragged_items.append(index.internalPointer());
|
||||
}
|
||||
}
|
||||
@@ -316,6 +316,7 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
|
||||
// Variables to deserialize into
|
||||
quintptr item_ptr;
|
||||
int r;
|
||||
quint64 enabled_streams;
|
||||
|
||||
// Loop through all data
|
||||
QUndoCommand* move_command = new QUndoCommand();
|
||||
@@ -323,7 +324,7 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
|
||||
move_command->setText(tr("Move Items"));
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
stream >> r >> item_ptr;
|
||||
stream >> enabled_streams >> r >> item_ptr;
|
||||
|
||||
Item* item = reinterpret_cast<Item*>(item_ptr);
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/playbackcontrols/dragbutton.h
|
||||
widget/playbackcontrols/dragbutton.cpp
|
||||
widget/playbackcontrols/playbackcontrols.h
|
||||
widget/playbackcontrols/playbackcontrols.cpp
|
||||
PARENT_SCOPE
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "dragbutton.h"
|
||||
|
||||
DragButton::DragButton(QWidget *parent) :
|
||||
QPushButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DragButton::mousePressEvent(QMouseEvent *event) {
|
||||
QPushButton::mousePressEvent(event);
|
||||
|
||||
emit MousePressed();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef DRAGBUTTON_H
|
||||
#define DRAGBUTTON_H
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
class DragButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DragButton(QWidget* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void MousePressed();
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent* event) override;
|
||||
|
||||
};
|
||||
|
||||
#endif // DRAGBUTTON_H
|
||||
@@ -37,12 +37,14 @@ PlaybackControls::PlaybackControls(QWidget *parent) :
|
||||
lower_control_layout->setSpacing(0);
|
||||
lower_control_layout->setMargin(0);
|
||||
|
||||
QSizePolicy lower_container_size_policy = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QSizePolicy lower_container_size_policy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
lower_container_size_policy.setHorizontalStretch(1);
|
||||
|
||||
// In the lower-left, we create a current timecode label wrapped in a QWidget for fixed sizing
|
||||
lower_left_container_ = new QWidget();
|
||||
lower_left_container_->setVisible(false);
|
||||
lower_left_container_->setSizePolicy(lower_container_size_policy);
|
||||
|
||||
lower_control_layout->addWidget(lower_left_container_);
|
||||
|
||||
QHBoxLayout* lower_left_layout = new QHBoxLayout(lower_left_container_);
|
||||
@@ -54,6 +56,12 @@ PlaybackControls::PlaybackControls(QWidget *parent) :
|
||||
lower_left_layout->addWidget(cur_tc_lbl_);
|
||||
lower_left_layout->addStretch();
|
||||
|
||||
// This is only here
|
||||
QWidget* blank_widget = new QWidget();
|
||||
//new QHBoxLayout(blank_widget);
|
||||
blank_widget->setSizePolicy(lower_container_size_policy);
|
||||
lower_control_layout->addWidget(blank_widget);
|
||||
|
||||
// In the lower-middle, we create playback control buttons
|
||||
QWidget* lower_middle_container = new QWidget();
|
||||
lower_middle_container->setSizePolicy(lower_container_size_policy);
|
||||
@@ -63,8 +71,6 @@ PlaybackControls::PlaybackControls(QWidget *parent) :
|
||||
lower_middle_layout->setSpacing(0);
|
||||
lower_middle_layout->setMargin(0);
|
||||
|
||||
lower_middle_layout->addStretch();
|
||||
|
||||
// Go To Start Button
|
||||
go_to_start_btn_ = new QPushButton();
|
||||
lower_middle_layout->addWidget(go_to_start_btn_);
|
||||
@@ -101,7 +107,20 @@ PlaybackControls::PlaybackControls(QWidget *parent) :
|
||||
lower_middle_layout->addWidget(go_to_end_btn_);
|
||||
connect(go_to_end_btn_, &QPushButton::clicked, this, &PlaybackControls::EndClicked);
|
||||
|
||||
lower_middle_layout->addStretch();
|
||||
QWidget* av_btn_widget = new QWidget();
|
||||
av_btn_widget->setSizePolicy(lower_container_size_policy);
|
||||
QHBoxLayout* av_btn_layout = new QHBoxLayout(av_btn_widget);
|
||||
av_btn_layout->setSpacing(0);
|
||||
av_btn_layout->setMargin(0);
|
||||
video_drag_btn_ = new DragButton();
|
||||
connect(video_drag_btn_, &QPushButton::clicked, this, &PlaybackControls::VideoClicked);
|
||||
connect(video_drag_btn_, &DragButton::MousePressed, this, &PlaybackControls::VideoPressed);
|
||||
av_btn_layout->addWidget(video_drag_btn_);
|
||||
audio_drag_btn_ = new DragButton();
|
||||
connect(audio_drag_btn_, &QPushButton::clicked, this, &PlaybackControls::AudioClicked);
|
||||
connect(audio_drag_btn_, &DragButton::MousePressed, this, &PlaybackControls::AudioPressed);
|
||||
av_btn_layout->addWidget(audio_drag_btn_);
|
||||
lower_control_layout->addWidget(av_btn_widget);
|
||||
|
||||
// The lower-right, we create another timecode label, this time to show the end timecode
|
||||
lower_right_container_ = new QWidget();
|
||||
@@ -121,6 +140,8 @@ PlaybackControls::PlaybackControls(QWidget *parent) :
|
||||
|
||||
SetTimebase(0);
|
||||
|
||||
SetAudioVideoDragButtonsVisible(false);
|
||||
|
||||
connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &PlaybackControls::TimecodeChanged);
|
||||
}
|
||||
|
||||
@@ -138,6 +159,12 @@ void PlaybackControls::SetTimebase(const rational &r)
|
||||
cur_tc_lbl_->setEnabled(!r.isNull());
|
||||
}
|
||||
|
||||
void PlaybackControls::SetAudioVideoDragButtonsVisible(bool e)
|
||||
{
|
||||
video_drag_btn_->setVisible(e);
|
||||
audio_drag_btn_->setVisible(e);
|
||||
}
|
||||
|
||||
void PlaybackControls::SetTime(const int64_t &r)
|
||||
{
|
||||
cur_tc_lbl_->SetValue(r);
|
||||
@@ -184,6 +211,8 @@ void PlaybackControls::UpdateIcons()
|
||||
pause_btn_->setIcon(icon::Pause);
|
||||
next_frame_btn_->setIcon(icon::NextFrame);
|
||||
go_to_end_btn_->setIcon(icon::GoToEnd);
|
||||
video_drag_btn_->setIcon(icon::Video);
|
||||
audio_drag_btn_->setIcon(icon::Audio);
|
||||
}
|
||||
|
||||
void PlaybackControls::TimecodeChanged()
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "dragbutton.h"
|
||||
#include "widget/slider/timeslider.h"
|
||||
|
||||
/**
|
||||
@@ -47,6 +48,8 @@ public:
|
||||
|
||||
void SetTimebase(const rational& r);
|
||||
|
||||
void SetAudioVideoDragButtonsVisible(bool e);
|
||||
|
||||
public slots:
|
||||
void SetTime(const int64_t &r);
|
||||
|
||||
@@ -87,6 +90,14 @@ signals:
|
||||
*/
|
||||
void EndClicked();
|
||||
|
||||
void AudioClicked();
|
||||
|
||||
void VideoClicked();
|
||||
|
||||
void AudioPressed();
|
||||
|
||||
void VideoPressed();
|
||||
|
||||
void TimeChanged(const int64_t& t);
|
||||
|
||||
protected:
|
||||
@@ -111,6 +122,8 @@ private:
|
||||
QPushButton* pause_btn_;
|
||||
QPushButton* next_frame_btn_;
|
||||
QPushButton* go_to_end_btn_;
|
||||
DragButton* video_drag_btn_;
|
||||
DragButton* audio_drag_btn_;
|
||||
|
||||
QStackedWidget* playpause_stack_;
|
||||
|
||||
|
||||
@@ -254,6 +254,22 @@ void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n)
|
||||
}
|
||||
}
|
||||
|
||||
TimelineWidget::DraggedFootage TimelineWidget::FootageToDraggedFootage(Footage *f)
|
||||
{
|
||||
return DraggedFootage(f, f->get_enabled_stream_flags());
|
||||
}
|
||||
|
||||
QList<TimelineWidget::DraggedFootage> TimelineWidget::FootageToDraggedFootage(QList<Footage *> footage)
|
||||
{
|
||||
QList<DraggedFootage> df;
|
||||
|
||||
foreach (Footage* f, footage) {
|
||||
df.append(FootageToDraggedFootage(f));
|
||||
}
|
||||
|
||||
return df;
|
||||
}
|
||||
|
||||
void TimelineWidget::SelectAll()
|
||||
{
|
||||
foreach (TimelineAndTrackView* view, views_) {
|
||||
|
||||
@@ -79,6 +79,32 @@ protected:
|
||||
virtual void DisconnectNodeInternal(ViewerOutput* n) override;
|
||||
|
||||
private:
|
||||
class DraggedFootage {
|
||||
public:
|
||||
DraggedFootage(Footage* f, quint64 streams) :
|
||||
footage_(f),
|
||||
streams_(streams)
|
||||
{
|
||||
}
|
||||
|
||||
Footage* footage() const {
|
||||
return footage_;
|
||||
}
|
||||
|
||||
const quint64& streams() const {
|
||||
return streams_;
|
||||
}
|
||||
|
||||
private:
|
||||
Footage* footage_;
|
||||
|
||||
quint64 streams_;
|
||||
|
||||
};
|
||||
|
||||
static DraggedFootage FootageToDraggedFootage(Footage* f);
|
||||
static QList<DraggedFootage> FootageToDraggedFootage(QList<Footage*> footage);
|
||||
|
||||
class Tool
|
||||
{
|
||||
public:
|
||||
@@ -227,16 +253,17 @@ private:
|
||||
virtual void DragLeave(QDragLeaveEvent *event) override;
|
||||
virtual void DragDrop(TimelineViewMouseEvent *event) override;
|
||||
|
||||
void PlaceAt(const QList<Footage*>& footage, const rational& start, bool insert);
|
||||
void PlaceAt(const QList<Footage*> &footage, const rational& start, bool insert);
|
||||
void PlaceAt(const QList<DraggedFootage> &footage, const rational& start, bool insert);
|
||||
|
||||
private:
|
||||
void FootageToGhosts(rational ghost_start, const QList<Footage*>& footage, const rational &dest_tb, const int &track_start);
|
||||
void FootageToGhosts(rational ghost_start, const QList<DraggedFootage>& footage, const rational &dest_tb, const int &track_start);
|
||||
|
||||
void PrepGhosts(const rational &frame, const int &track_index);
|
||||
|
||||
void DropGhosts(bool insert);
|
||||
|
||||
QList<Footage*> dragged_footage_;
|
||||
QList<DraggedFootage> dragged_footage_;
|
||||
|
||||
int import_pre_buffer_;
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event)
|
||||
// Variables to deserialize into
|
||||
quintptr item_ptr;
|
||||
int r;
|
||||
quint64 enabled_streams;
|
||||
|
||||
// Set drag start position
|
||||
drag_start_ = event->GetCoordinates();
|
||||
@@ -86,7 +87,7 @@ void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event)
|
||||
snap_points_.clear();
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
stream >> r >> item_ptr;
|
||||
stream >> enabled_streams >> r >> item_ptr;
|
||||
|
||||
// Get Item object
|
||||
Item* item = reinterpret_cast<Item*>(item_ptr);
|
||||
@@ -95,7 +96,7 @@ void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event)
|
||||
if (item->type() == Item::kFootage) {
|
||||
|
||||
// If the Item is Footage, we can create a Ghost from it
|
||||
dragged_footage_.append(static_cast<Footage*>(item));
|
||||
dragged_footage_.append(DraggedFootage(static_cast<Footage*>(item), enabled_streams));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -175,7 +176,6 @@ void TimelineWidget::ImportTool::DragLeave(QDragLeaveEvent* event)
|
||||
void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event)
|
||||
{
|
||||
if (!dragged_footage_.isEmpty()) {
|
||||
|
||||
DropGhosts(event->GetModifiers() & Qt::ControlModifier);
|
||||
|
||||
event->accept();
|
||||
@@ -185,6 +185,11 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event)
|
||||
}
|
||||
|
||||
void TimelineWidget::ImportTool::PlaceAt(const QList<Footage *> &footage, const rational &start, bool insert)
|
||||
{
|
||||
PlaceAt(FootageToDraggedFootage(footage), start, insert);
|
||||
}
|
||||
|
||||
void TimelineWidget::ImportTool::PlaceAt(const QList<DraggedFootage> &footage, const rational &start, bool insert)
|
||||
{
|
||||
dragged_footage_ = footage;
|
||||
|
||||
@@ -196,9 +201,9 @@ void TimelineWidget::ImportTool::PlaceAt(const QList<Footage *> &footage, const
|
||||
DropGhosts(insert);
|
||||
}
|
||||
|
||||
void TimelineWidget::ImportTool::FootageToGhosts(rational ghost_start, const QList<Footage *> &footage_list, const rational& dest_tb, const int& track_start)
|
||||
void TimelineWidget::ImportTool::FootageToGhosts(rational ghost_start, const QList<DraggedFootage> &footage_list, const rational& dest_tb, const int& track_start)
|
||||
{
|
||||
foreach (Footage* footage, footage_list) {
|
||||
foreach (const DraggedFootage& footage, footage_list) {
|
||||
|
||||
// Each stream is offset by one track per track "type", we keep track of them in this vector
|
||||
QVector<int> track_offsets(Timeline::kTrackTypeCount);
|
||||
@@ -206,12 +211,18 @@ void TimelineWidget::ImportTool::FootageToGhosts(rational ghost_start, const QLi
|
||||
|
||||
rational footage_duration;
|
||||
|
||||
quint64 enabled_streams = footage.streams();
|
||||
|
||||
// Loop through all streams in footage
|
||||
foreach (StreamPtr stream, footage->streams()) {
|
||||
foreach (StreamPtr stream, footage.footage()->streams()) {
|
||||
Timeline::TrackType track_type = TrackTypeFromStreamType(stream->type());
|
||||
|
||||
quint64 cached_enabled_streams = enabled_streams;
|
||||
enabled_streams >>= 1;
|
||||
|
||||
// Check if this stream has a compatible TrackList
|
||||
if (track_type == Timeline::kTrackTypeNone || !stream->enabled()) {
|
||||
if (track_type == Timeline::kTrackTypeNone
|
||||
|| !(cached_enabled_streams & 0x1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -322,7 +333,13 @@ void TimelineWidget::ImportTool::DropGhosts(bool insert)
|
||||
|
||||
if (behavior == kDWSAuto) {
|
||||
|
||||
new_sequence->set_parameters_from_footage(dragged_footage_);
|
||||
QList<Footage*> footage_only;
|
||||
|
||||
foreach (const DraggedFootage& df, dragged_footage_) {
|
||||
footage_only.append(df.footage());
|
||||
}
|
||||
|
||||
new_sequence->set_parameters_from_footage(footage_only);
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
|
||||
viewer_node_ = new ViewerOutput();
|
||||
|
||||
connect(gl_widget_, &ViewerGLWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
|
||||
|
||||
controls_->SetAudioVideoDragButtonsVisible(true);
|
||||
connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag);
|
||||
connect(controls_, &PlaybackControls::AudioPressed, this, &FootageViewerWidget::StartAudioDrag);
|
||||
}
|
||||
|
||||
Footage *FootageViewerWidget::GetFootage() const
|
||||
@@ -69,10 +73,10 @@ void FootageViewerWidget::SetFootage(Footage *footage)
|
||||
|
||||
TimelinePoints *FootageViewerWidget::ConnectTimelinePoints()
|
||||
{
|
||||
return footage_ ? footage_ : nullptr;
|
||||
return footage_;
|
||||
}
|
||||
|
||||
void FootageViewerWidget::StartFootageDrag()
|
||||
void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enable_audio)
|
||||
{
|
||||
if (!GetFootage()) {
|
||||
return;
|
||||
@@ -84,10 +88,41 @@ void FootageViewerWidget::StartFootageDrag()
|
||||
QByteArray encoded_data;
|
||||
QDataStream stream(&encoded_data, QIODevice::WriteOnly);
|
||||
|
||||
stream << -1 << reinterpret_cast<quintptr>(GetFootage());
|
||||
quint64 enabled_stream_flags = GetFootage()->get_enabled_stream_flags();
|
||||
|
||||
// Disable streams that have been disabled
|
||||
if (!enable_video || !enable_audio) {
|
||||
quint64 stream_disabler = 0x1;
|
||||
|
||||
foreach (StreamPtr s, GetFootage()->streams()) {
|
||||
if ((s->type() == Stream::kVideo && !enable_video)
|
||||
|| (s->type() == Stream::kAudio && !enable_audio)) {
|
||||
enabled_stream_flags &= ~stream_disabler;
|
||||
}
|
||||
|
||||
stream_disabler <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
stream << enabled_stream_flags << -1 << reinterpret_cast<quintptr>(GetFootage());
|
||||
|
||||
mimedata->setData("application/x-oliveprojectitemdata", encoded_data);
|
||||
drag->setMimeData(mimedata);
|
||||
|
||||
drag->exec();
|
||||
}
|
||||
|
||||
void FootageViewerWidget::StartFootageDrag()
|
||||
{
|
||||
StartFootageDragInternal(true, true);
|
||||
}
|
||||
|
||||
void FootageViewerWidget::StartVideoDrag()
|
||||
{
|
||||
StartFootageDragInternal(true, false);
|
||||
}
|
||||
|
||||
void FootageViewerWidget::StartAudioDrag()
|
||||
{
|
||||
StartFootageDragInternal(false, true);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ protected:
|
||||
virtual TimelinePoints* ConnectTimelinePoints() override;
|
||||
|
||||
private:
|
||||
void StartFootageDragInternal(bool enable_video, bool enable_audio);
|
||||
|
||||
Footage* footage_;
|
||||
|
||||
VideoInput* video_node_;
|
||||
@@ -30,6 +32,10 @@ private:
|
||||
private slots:
|
||||
void StartFootageDrag();
|
||||
|
||||
void StartVideoDrag();
|
||||
|
||||
void StartAudioDrag();
|
||||
|
||||
};
|
||||
|
||||
#endif // FOOTAGEVIEWERWIDGET_H
|
||||
|
||||
@@ -123,6 +123,8 @@ protected:
|
||||
|
||||
ViewerGLWidget* gl_widget_;
|
||||
|
||||
PlaybackControls* controls_;
|
||||
|
||||
private:
|
||||
void UpdateTimeInternal(int64_t i);
|
||||
|
||||
@@ -140,8 +142,6 @@ private:
|
||||
|
||||
ViewerSizer* sizer_;
|
||||
|
||||
PlaybackControls* controls_;
|
||||
|
||||
qint64 start_msec_;
|
||||
int64_t start_timestamp_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user