From bb32048c653a86371e26f891576bee4b362a5ea6 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 7 Apr 2021 13:08:25 +1000 Subject: [PATCH] use frame rate and timebase less interchangeably --- app/codec/ffmpeg/ffmpegencoder.cpp | 4 +- app/common/timecodefunctions.cpp | 8 ++++ app/dialog/export/export.cpp | 2 +- app/node/output/viewer/viewer.cpp | 39 ++++--------------- app/node/output/viewer/viewer.h | 2 +- app/project/item/footage/footage.cpp | 33 ++++++++++++++++ app/render/audioparams.h | 12 +++--- app/render/framehashcache.cpp | 2 + app/render/renderprocessor.cpp | 2 +- app/render/videoparams.cpp | 3 +- app/render/videoparams.h | 5 +++ app/task/export/export.cpp | 2 +- app/task/render/render.cpp | 2 +- app/widget/timebased/timebasedwidget.cpp | 36 ++++++++++++------ app/widget/timelinewidget/timelinewidget.cpp | 4 +- app/widget/timelinewidget/tool/import.cpp | 2 +- app/widget/videoparamedit/videoparamedit.cpp | 40 ++++++++++++-------- app/widget/videoparamedit/videoparamedit.h | 3 ++ app/widget/viewer/viewer.cpp | 38 +++++++++++++++++++ app/widget/viewer/viewer.h | 4 ++ app/widget/viewer/viewerdisplay.cpp | 23 +++++++---- app/widget/viewer/viewerdisplay.h | 6 +-- 22 files changed, 187 insertions(+), 85 deletions(-) diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 31dc63198..3098b8bb1 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -219,7 +219,7 @@ void FFmpegEncoder::WriteAudio(AudioParams pcm_info, QIODevice* file) // If not, use another frame size if (params().video_enabled()) { // If we're encoding video, use enough samples to cover roughly one frame of video - maximum_frame_samples = params().audio_params().time_to_samples(params().video_params().time_base()); + maximum_frame_samples = params().audio_params().time_to_samples(params().video_params().frame_rate_as_time_base()); } else { // If no video, just use an arbitrary number maximum_frame_samples = 256; @@ -484,7 +484,7 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AV codec_ctx->width = params().video_params().width(); codec_ctx->height = params().video_params().height(); codec_ctx->sample_aspect_ratio = params().video_params().pixel_aspect_ratio().toAVRational(); - codec_ctx->time_base = params().video_params().time_base().toAVRational(); + codec_ctx->time_base = params().video_params().frame_rate_as_time_base().toAVRational(); codec_ctx->pix_fmt = av_get_pix_fmt(params().video_pix_fmt().toUtf8()); if (params().video_params().interlacing() != VideoParams::kInterlaceNone) { diff --git a/app/common/timecodefunctions.cpp b/app/common/timecodefunctions.cpp index 613fe8aa9..491f76821 100644 --- a/app/common/timecodefunctions.cpp +++ b/app/common/timecodefunctions.cpp @@ -281,11 +281,19 @@ int64_t Timecode::time_to_timestamp(const double &time, const rational &timebase int64_t Timecode::rescale_timestamp(const int64_t &ts, const rational &source, const rational &dest) { + if (source == dest) { + return ts; + } + return qRound64(static_cast(ts) * source.toDouble() / dest.toDouble()); } int64_t Timecode::rescale_timestamp_ceil(const int64_t &ts, const rational &source, const rational &dest) { + if (source == dest) { + return ts; + } + return qCeil(static_cast(ts) * source.toDouble() / dest.toDouble()); } diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index 642678855..d5177afef 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -195,7 +195,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : video_tab_->width_slider()->SetDefaultValue(vp.width()); video_tab_->height_slider()->SetValue(vp.height()); video_tab_->height_slider()->SetDefaultValue(vp.height()); - video_tab_->frame_rate_combobox()->SetFrameRate(vp.time_base().flipped()); + video_tab_->frame_rate_combobox()->SetFrameRate(vp.frame_rate()); video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(vp.pixel_aspect_ratio()); video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()["OnlinePixelFormat"].toInt())); video_tab_->interlaced_combobox()->SetInterlaceMode(vp.interlacing()); diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 48b64eb48..2dddad416 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -92,30 +92,13 @@ QString ViewerOutput::Description() const QString ViewerOutput::duration() const { - /*rational timeline_length = GetLength(); - - rational timebase = GetVideoParams().time_base(); - - int64_t timestamp = Timecode::time_to_timestamp(timeline_length, timebase); - - return Timecode::timestamp_to_timecode(timestamp, timebase, Core::instance()->GetTimecodeDisplay());*/ // Try video first VideoParams video = GetFirstEnabledVideoStream(); if (video.is_valid() && video.video_type() != VideoParams::kVideoTypeStill) { - int64_t duration = video.duration(); + rational frame_rate_timebase = video.frame_rate_as_time_base(); - rational frame_rate_timebase = video.frame_rate().flipped(); - if (frame_rate_timebase.isNull()) { - frame_rate_timebase = video.time_base(); - } - - if (video.time_base() != frame_rate_timebase) { - // Convert from timebase to frame rate - duration = Timecode::rescale_timestamp_ceil(duration, video.time_base(), frame_rate_timebase); - } - - return Timecode::timestamp_to_timecode(duration, + return Timecode::timestamp_to_timecode(Timecode::rescale_timestamp_ceil(video.duration(), video.time_base(), frame_rate_timebase), frame_rate_timebase, Core::instance()->GetTimecodeDisplay()); } @@ -147,13 +130,7 @@ QString ViewerOutput::rate() const VideoParams video_stream = GetFirstEnabledVideoStream(); if (video_stream.video_type() != VideoParams::kVideoTypeStill) { - rational using_tb = video_stream.frame_rate(); - - if (using_tb.isNull()) { - using_tb = video_stream.time_base().flipped(); - } - - return tr("%1 FPS").arg(using_tb.toDouble()); + return tr("%1 FPS").arg(video_stream.frame_rate().toDouble()); } } else if (HasEnabledAudioStreams()) { // No video streams, return audio @@ -414,7 +391,7 @@ void ViewerOutput::InputValueChangedEvent(const QString &input, int element) VideoParams new_video_params = GetVideoParams(); bool size_changed = cached_video_params_.width() != new_video_params.width() || cached_video_params_.height() != new_video_params.height(); - bool timebase_changed = cached_video_params_.time_base() != new_video_params.time_base(); + bool frame_rate_changed = cached_video_params_.frame_rate() != new_video_params.frame_rate(); bool pixel_aspect_changed = cached_video_params_.pixel_aspect_ratio() != new_video_params.pixel_aspect_ratio(); bool interlacing_changed = cached_video_params_.interlacing() != new_video_params.interlacing(); @@ -430,9 +407,9 @@ void ViewerOutput::InputValueChangedEvent(const QString &input, int element) emit InterlacingChanged(new_video_params.interlacing()); } - if (timebase_changed) { - video_frame_cache_.SetTimebase(new_video_params.time_base()); - emit TimebaseChanged(new_video_params.time_base()); + if (frame_rate_changed) { + video_frame_cache_.SetTimebase(new_video_params.frame_rate_as_time_base()); + emit FrameRateChanged(new_video_params.frame_rate()); } emit VideoParamsChanged(); @@ -479,7 +456,7 @@ void ViewerOutput::set_parameters_from_footage(const QVector foo // prioritize using_timebase = GetVideoParams().time_base(); } else { - using_timebase = s.frame_rate().flipped(); + using_timebase = s.frame_rate_as_time_base(); found_video_params = true; } diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index cb4e41d1c..423a32481 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -150,7 +150,7 @@ public: static const uint64_t kVideoParamEditMask; signals: - void TimebaseChanged(const rational&); + void FrameRateChanged(const rational&); void LengthChanged(const rational& length); diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index 8c842347f..b26783311 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -123,6 +123,39 @@ void Footage::InputValueChangedEvent(const QString &input, int element) AddStream(Track::kVideo, QVariant::fromValue(footage_info.GetVideoStreams().at(i))); } + if (!footage_info.GetVideoStreams().isEmpty()) { + // FIXME: This will break on multiple video streams. Currently we don't have + // infrastructure for different properties per element. We'll see if this becomes + // a problem. + VideoParams vp = footage_info.GetVideoStreams().first(); + + uint64_t video_param_mask = 0; + + video_param_mask |= VideoParamEdit::kEnabled; + video_param_mask |= VideoParamEdit::kColorspace; + video_param_mask |= VideoParamEdit::kPixelAspect; + video_param_mask |= VideoParamEdit::kInterlacing; + video_param_mask |= VideoParamEdit::kFrameRateIsArbitrary; + + if (vp.channel_count() == VideoParams::kRGBAChannelCount) { + // Add premultiplied setting if this footage has an alpha channel + video_param_mask |= VideoParamEdit::kPremultipliedAlpha; + } + + if (vp.video_type() == VideoParams::kVideoTypeVideo) { + // This is video, ensure that the frame rate does not overwrite the timebase + video_param_mask |= VideoParamEdit::kFrameRateIsNotTimebase; + } else { + // This is not a video, so it's either a still image or an image sequence + video_param_mask |= VideoParamEdit::kIsImageSequence; + video_param_mask |= VideoParamEdit::kStartTime; + video_param_mask |= VideoParamEdit::kEndTime; + video_param_mask |= VideoParamEdit::kFrameRate; + } + + SetInputProperty(kVideoParamsInput, QStringLiteral("mask"), QVariant::fromValue(video_param_mask)); + } + for (int i=0; iGetConnectedTextureOutput(); if (texture_output.IsValid()) { table = GenerateTable(texture_output.node(), texture_output.output(), - TimeRange(time, time + video_params.time_base())); + TimeRange(time, time + video_params.frame_rate_as_time_base())); } TexturePtr texture = table.Get(NodeValue::kTexture).value(); diff --git a/app/render/videoparams.cpp b/app/render/videoparams.cpp index 4dd95c2e8..134d13076 100644 --- a/app/render/videoparams.cpp +++ b/app/render/videoparams.cpp @@ -112,7 +112,8 @@ VideoParams::VideoParams(int width, int height, const rational &time_base, Forma channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), interlacing_(interlacing), - divider_(divider) + divider_(divider), + frame_rate_(time_base.flipped()) { calculate_effective_size(); validate_pixel_aspect_ratio(); diff --git a/app/render/videoparams.h b/app/render/videoparams.h index ba51a2256..1e01226e0 100644 --- a/app/render/videoparams.h +++ b/app/render/videoparams.h @@ -122,6 +122,11 @@ public: time_base_ = r; } + rational frame_rate_as_time_base() const + { + return frame_rate_.flipped(); + } + int divider() const { return divider_; diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index bc69e8a7c..45ddc32c8 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -163,7 +163,7 @@ void ExportTask::FrameDownloaded(FramePtr f, const QByteArray &hash, const QVect forever { rational real_time = Timecode::timestamp_to_time(frame_time_, - viewer()->GetVideoParams().time_base()); + viewer()->GetVideoParams().frame_rate_as_time_base()); if (!time_map_.contains(real_time)) { break; diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index 913a544ac..0511f808c 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -51,7 +51,7 @@ bool RenderTask::Render(ColorManager* manager, double progress_counter = 0; double total_length = 0; - double video_frame_sz = video_params().time_base().toDouble(); + double video_frame_sz = video_params().frame_rate_as_time_base().toDouble(); // Store real time before any rendering takes place qint64 job_time = QDateTime::currentMSecsSinceEpoch(); diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index 64e584e52..16f5e3e82 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -74,46 +74,58 @@ ViewerOutput *TimeBasedWidget::GetConnectedNode() const void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) { + // Ignore no-op if (viewer_node_ == node) { return; } if (viewer_node_) { + // Call potential derivative functions for disconnecting the viewer node DisconnectNodeInternal(viewer_node_); + // Disconnect length changed signal disconnect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll); - disconnect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &TimeBasedWidget::SetTimebase); - if (auto_set_timebase_) { - SetTimebase(rational()); - } + // Reset timebase to null + SetTimebase(rational()); + // Disconnect ruler and scrollbar from timeline points ruler()->ConnectTimelinePoints(nullptr); scrollbar_->ConnectTimelinePoints(nullptr); } + // Set viewer node viewer_node_ = node; + // Call derivatives ConnectedNodeChanged(viewer_node_); if (viewer_node_) { + // Connect length changed signal connect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll); + // Connect ruler and scrollbar to timeline points ruler()->ConnectTimelinePoints(viewer_node_->GetTimelinePoints()); scrollbar_->ConnectTimelinePoints(viewer_node_->GetTimelinePoints()); + // If we're setting the timebase, set it automatically based on the video and audio parameters if (auto_set_timebase_) { - if (!viewer_node_->GetVideoParams().time_base().isNull()) { - SetTimebase(viewer_node_->GetVideoParams().time_base()); - } else if (viewer_node_->GetAudioParams().sample_rate() > 0) { - SetTimebase(viewer_node_->GetAudioParams().time_base()); - } else { - SetTimebase(rational()); - } + rational video_tb = viewer_node_->GetVideoParams().frame_rate_as_time_base(); - connect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &TimeBasedWidget::SetTimebase); + if (!video_tb.isNull()) { + SetTimebase(video_tb); + } else { + rational audio_tb = viewer_node_->GetAudioParams().sample_rate_as_time_base(); + + if (!audio_tb.isNull()) { + SetTimebase(audio_tb); + } else { + SetTimebase(rational()); + } + } } + // Call derivatives ConnectNodeInternal(viewer_node_); } diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 277034544..543d601fc 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -224,11 +224,10 @@ void TimelineWidget::ConnectNodeInternal(ViewerOutput *n) connect(s, &Sequence::TrackAdded, this, &TimelineWidget::AddTrack); connect(s, &Sequence::TrackRemoved, this, &TimelineWidget::RemoveTrack); - connect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); ruler()->SetPlaybackCache(n->video_frame_cache()); - SetTimebase(n->GetVideoParams().time_base()); + SetTimebase(n->GetVideoParams().frame_rate_as_time_base()); for (int i=0;i(i); @@ -253,7 +252,6 @@ void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n) disconnect(s, &Sequence::TrackAdded, this, &TimelineWidget::AddTrack); disconnect(s, &Sequence::TrackRemoved, this, &TimelineWidget::RemoveTrack); - disconnect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); DeselectAll(); diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index a2855ae07..f40cc488c 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -281,7 +281,7 @@ void ImportTool::PrepGhosts(const rational& frame, const int& track_index) if (parent()->GetConnectedNode()) { FootageToGhosts(frame, dragged_footage_, - parent()->timebase(), + parent()->GetConnectedNode()->GetVideoParams().time_base(), track_index); } } diff --git a/app/widget/videoparamedit/videoparamedit.cpp b/app/widget/videoparamedit/videoparamedit.cpp index 8561db5e9..146b82424 100644 --- a/app/widget/videoparamedit/videoparamedit.cpp +++ b/app/widget/videoparamedit/videoparamedit.cpp @@ -97,6 +97,10 @@ VideoParamEdit::VideoParamEdit(QWidget* parent) : connect(frame_rate_combobox_, static_cast(&FrameRateComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); layout->addWidget(frame_rate_combobox_, row, 1); + frame_rate_slider_ = new FloatSlider(); + connect(frame_rate_slider_, &FloatSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(frame_rate_slider_, row, 1); + row++; // Pixel Aspect Ratio @@ -215,7 +219,8 @@ void VideoParamEdit::SetParameterMask(uint64_t mask) depth_slider_->setVisible(mask & kDepth); frame_rate_lbl_->setVisible(mask & kFrameRate); - frame_rate_combobox_->setVisible(mask & kFrameRate); + frame_rate_combobox_->setVisible((mask & kFrameRate) && (mask & ~kFrameRateIsArbitrary)); + frame_rate_slider_->setVisible((mask & kFrameRate) && (mask & kFrameRateIsArbitrary)); pixel_aspect_lbl_->setVisible(mask & kPixelAspect); pixel_aspect_combobox_->setVisible(mask & kPixelAspect); @@ -263,12 +268,22 @@ VideoParams VideoParamEdit::GetVideoParams() const p.set_height(height_slider_->GetValue()); p.set_depth(depth_slider_->GetValue()); - p.set_frame_rate(frame_rate_combobox_->GetFrameRate()); - if (mask_ & kFrameRateIsNotTimebase) { - // Frame rate editor will only edit the frame rate - p.set_time_base(timebase_temp_); - } else { - p.set_time_base(frame_rate_combobox_->GetFrameRate().flipped()); + { + rational using_frame_rate; + + if (mask_ & kFrameRateIsArbitrary) { + using_frame_rate = rational::fromDouble(frame_rate_slider_->GetValue()); + } else { + using_frame_rate = frame_rate_combobox_->GetFrameRate(); + } + + p.set_frame_rate(using_frame_rate); + if (mask_ & kFrameRateIsNotTimebase) { + // Frame rate editor will only edit the frame rate + p.set_time_base(timebase_temp_); + } else { + p.set_time_base(using_frame_rate.flipped()); + } } p.set_pixel_aspect_ratio(pixel_aspect_combobox_->GetPixelAspectRatio()); @@ -295,14 +310,9 @@ void VideoParamEdit::SetVideoParams(const VideoParams &p) height_slider_->SetValue(p.height()); depth_slider_->SetValue(p.depth()); - if (mask_ & kFrameRateIsNotTimebase) { - // Frame rate editor will only edit the frame rate - frame_rate_combobox_->SetFrameRate(p.frame_rate()); - timebase_temp_ = p.time_base(); - } else { - // Frame rate editor will edit both frame rate and time base - frame_rate_combobox_->SetFrameRate(p.time_base().flipped()); - } + frame_rate_combobox_->SetFrameRate(p.frame_rate()); + frame_rate_slider_->SetValue(p.frame_rate().toDouble()); + timebase_temp_ = p.time_base(); pixel_aspect_combobox_->SetPixelAspectRatio(p.pixel_aspect_ratio()); interlaced_combobox_->SetInterlaceMode(p.interlacing()); diff --git a/app/widget/videoparamedit/videoparamedit.h b/app/widget/videoparamedit/videoparamedit.h index 91c678e1f..da2684a94 100644 --- a/app/widget/videoparamedit/videoparamedit.h +++ b/app/widget/videoparamedit/videoparamedit.h @@ -27,6 +27,7 @@ #include "render/colormanager.h" #include "render/videoparams.h" +#include "widget/slider/floatslider.h" #include "widget/slider/integerslider.h" #include "widget/standardcombos/frameratecombobox.h" #include "widget/standardcombos/interlacedcombobox.h" @@ -60,6 +61,7 @@ public: kPremultipliedAlpha = 0x2000, kColorspace = 0x4000, kFrameRateIsNotTimebase = 0x8000, + kFrameRateIsArbitrary = 0x10000 }; void SetParameterMask(uint64_t mask); @@ -143,6 +145,7 @@ private: IntegerSlider* depth_slider_; QLabel* frame_rate_lbl_; FrameRateComboBox* frame_rate_combobox_; + FloatSlider* frame_rate_slider_; QLabel* pixel_aspect_lbl_; PixelAspectRatioComboBox* pixel_aspect_combobox_; QLabel* interlaced_lbl_; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index d877370e1..24a14287a 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -71,10 +71,13 @@ ViewerWidget::ViewerWidget(QWidget *parent) : stack_->addWidget(sizer_); display_widget_ = new ViewerDisplayWidget(); + display_widget_->setAcceptDrops(true); connect(display_widget_, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); connect(display_widget_, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor); connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); + connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered); + connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped); connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom); connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate); connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove); @@ -118,6 +121,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) : SetAutoMaxScrollBar(true); instances_.append(this); + + setAcceptDrops(true); } ViewerWidget::~ViewerWidget() @@ -1214,4 +1219,37 @@ void ViewerWidget::ViewerShiftedRange(const rational &from, const rational &to) } } +void ViewerWidget::DragEntered(QDragEnterEvent* event) +{ + if (event->mimeData()->formats().contains(QStringLiteral("application/x-oliveprojectitemdata"))) { + event->accept(); + } +} + +void ViewerWidget::Dropped(QDropEvent *event) +{ + QByteArray mimedata = event->mimeData()->data(QStringLiteral("application/x-oliveprojectitemdata")); + QDataStream stream(&mimedata, QIODevice::ReadOnly); + + // Variables to deserialize into + quintptr item_ptr = 0; + QVector enabled_streams; + + while (!stream.atEnd()) { + stream >> enabled_streams >> item_ptr; + + // We only need the one item + break; + } + + if (item_ptr) { + Node* item = reinterpret_cast(item_ptr); + ViewerOutput* viewer = dynamic_cast(item); + + if (viewer) { + ConnectViewerNode(viewer); + } + } +} + } diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 5a275ceb3..7e3f4fab8 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -288,6 +288,10 @@ private slots: void TimeChangedFromWaveform(qint64 t); + void DragEntered(QDragEnterEvent* event); + + void Dropped(QDropEvent* event); + }; } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index e3da4f81f..24d5a853a 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -278,20 +278,29 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) void ViewerDisplayWidget::dragEnterEvent(QDragEnterEvent *event) { - emit DragEntered(); - super::dragEnterEvent(event); + emit DragEntered(event); + + if (!event->isAccepted()) { + super::dragEnterEvent(event); + } } void ViewerDisplayWidget::dragLeaveEvent(QDragLeaveEvent *event) { - emit DragLeft(); - super::dragLeaveEvent(event); + emit DragLeft(event); + + if (!event->isAccepted()) { + super::dragLeaveEvent(event); + } } void ViewerDisplayWidget::dropEvent(QDropEvent *event) { - emit Dropped(); - super::dropEvent(event); + emit Dropped(event); + + if (!event->isAccepted()) { + super::dropEvent(event); + } } void ViewerDisplayWidget::OnPaint() @@ -345,7 +354,7 @@ void ViewerDisplayWidget::OnPaint() rational node_time = GetGizmoTime(); gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, - node_time + gizmo_params_.time_base())); + node_time + gizmo_params_.frame_rate_as_time_base())); QPainter p(inner_widget()); p.setWorldTransform(GenerateGizmoTransform()); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index a765ebabd..920ea91b6 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -170,11 +170,11 @@ signals: */ void CursorColor(const Color& reference, const Color& display); - void DragEntered(); + void DragEntered(QDragEnterEvent* event); - void DragLeft(); + void DragLeft(QDragLeaveEvent* event); - void Dropped(); + void Dropped(QDropEvent* event); protected: /**