diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b22b69ced..4998e2a99 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -94,6 +94,7 @@ if(MSVC) /external:anglebrackets /external:W0 "$<$:/O2>" + "$<$:/MP>" ) else() target_compile_options( @@ -110,7 +111,7 @@ else() endif() if(UNIX AND NOT APPLE) - target_compile_options( + target_link_options( ${OLIVE_TARGET} PRIVATE -rdynamic @@ -155,6 +156,12 @@ if (WIN32) PRIVATE DbgHelp ) +elseif (APPLE) + target_link_libraries( + ${OLIVE_TARGET} + PRIVATE + "-framework ApplicationServices" + ) endif() set(OLIVE_TS_FILES diff --git a/app/config/config.cpp b/app/config/config.cpp index c6e26a454..e3024ee18 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -98,8 +98,8 @@ void Config::SetDefaults() config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); config_map_["DiskCacheSize"] = 20.0; - config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(2)); - config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(10)); + config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(1)); + config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(5)); config_map_["ClearDiskCacheOnClose"] = false; config_map_["DefaultSequenceWidth"] = 1920; diff --git a/app/dialog/footageproperties/footageproperties.cpp b/app/dialog/footageproperties/footageproperties.cpp index 3fe507906..484127021 100644 --- a/app/dialog/footageproperties/footageproperties.cpp +++ b/app/dialog/footageproperties/footageproperties.cpp @@ -109,7 +109,7 @@ FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent, Footage *foota // Auto-select first item that actually has properties if (first_usable_stream >= 0) { - track_list->item(first_usable_stream)->setSelected(true); + track_list->setCurrentRow(first_usable_stream); } track_list->setFocus(); } diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp index e8dc50195..7f90d2bd2 100644 --- a/app/dialog/projectproperties/projectproperties.cpp +++ b/app/dialog/projectproperties/projectproperties.cpp @@ -44,10 +44,12 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : setWindowTitle(tr("Project Properties for '%1'").arg(working_project_->name())); + QTabWidget* tabs = new QTabWidget; + layout->addWidget(tabs); + { // Color management group - QGroupBox* color_group = new QGroupBox(); - color_group->setTitle(tr("Color Management")); + QWidget* color_group = new QWidget(); QGridLayout* color_layout = new QGridLayout(color_group); @@ -72,18 +74,19 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : color_layout->addWidget(browse_btn, 0, 2); connect(browse_btn, &QPushButton::clicked, this, &ProjectPropertiesDialog::BrowseForOCIOConfig); - layout->addWidget(color_group); - ocio_filename_->setText(working_project_->color_manager()->GetConfigFilename()); connect(ocio_filename_, &QLineEdit::textChanged, this, &ProjectPropertiesDialog::OCIOFilenameUpdated); OCIOFilenameUpdated(); + + tabs->addTab(color_group, tr("Color Management")); } + + { // Paths group - QGroupBox* paths_group = new QGroupBox(); - paths_group->setTitle(tr("Paths")); + QWidget* paths_group = new QWidget(); QGridLayout* paths_layout = new QGridLayout(paths_group); @@ -104,7 +107,7 @@ ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : paths_layout->addWidget(proxy_path_->browse_btn(), row, 2); paths_layout->addWidget(proxy_path_->default_box(), row, 3); - layout->addWidget(paths_group); + tabs->addTab(paths_group, tr("Paths")); } QDialogButtonBox* dialog_btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, diff --git a/app/render/backend/audiorenderbackend.cpp b/app/render/backend/audiorenderbackend.cpp index 9e819c0c8..368d70195 100644 --- a/app/render/backend/audiorenderbackend.cpp +++ b/app/render/backend/audiorenderbackend.cpp @@ -124,7 +124,7 @@ TimeRange AudioRenderBackend::PopNextFrameFromQueue() return range; } -void AudioRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range) +void AudioRenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) { if (!ic_from_conform_) { // Cancel any ranges waiting on a conform here since obviously the contents have changed @@ -153,7 +153,7 @@ void AudioRenderBackend::InvalidateCacheInternal(const rational &start_range, co } } - RenderBackend::InvalidateCacheInternal(start_range, end_range); + RenderBackend::InvalidateCacheInternal(start_range, end_range, only_visible); } void AudioRenderBackend::ListenForConformSignal(AudioStreamPtr s) diff --git a/app/render/backend/audiorenderbackend.h b/app/render/backend/audiorenderbackend.h index ef6e6a090..6c6dd04f2 100644 --- a/app/render/backend/audiorenderbackend.h +++ b/app/render/backend/audiorenderbackend.h @@ -67,7 +67,7 @@ protected: virtual TimeRange PopNextFrameFromQueue() override; - virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range) override; + virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) override; private: struct ConformWaitInfo { diff --git a/app/render/backend/renderbackend.cpp b/app/render/backend/renderbackend.cpp index 8a4acb21e..502f35916 100644 --- a/app/render/backend/renderbackend.cpp +++ b/app/render/backend/renderbackend.cpp @@ -259,6 +259,8 @@ void RenderBackend::CacheNext() SetWorkerBusyState(worker, true); cancel_dialog_->WorkerStarted(); + WorkerAboutToStartEvent(worker); + QMetaObject::invokeMethod(worker, "Render", Qt::QueuedConnection, @@ -290,24 +292,14 @@ void RenderBackend::CancelQueue() cancel_dialog_->RunIfWorkersAreBusy(); } +void RenderBackend::InvalidateVisible(const TimeRange &range, NodeInput *from) +{ + InvalidateCacheVeryInternal(range, from, true); +} + void RenderBackend::InvalidateCache(const TimeRange &range, NodeInput *from) { - // Adjust range to min/max values - rational start_range_adj = qMax(rational(0), range.in()); - rational end_range_adj = qMin(GetSequenceLength(), range.out()); - - qDebug() << "Cache invalidated between" - << start_range_adj.toDouble() - << "and" - << end_range_adj.toDouble(); - - if (from) { - // Queue value update - qDebug() << " from" << from->parentNode()->id() << "::" << from->id(); - QueueValueUpdate(from); - } - - InvalidateCacheInternal(start_range_adj, end_range_adj); + InvalidateCacheVeryInternal(range, from, false); } bool RenderBackend::ViewerIsConnected() const @@ -349,6 +341,26 @@ void RenderBackend::SetWorkerBusyState(RenderWorker *worker, bool busy) processor_busy_state_.replace(processors_.indexOf(worker), busy); } +void RenderBackend::InvalidateCacheVeryInternal(const TimeRange &range, NodeInput *from, bool only_visible) +{ + // Adjust range to min/max values + rational start_range_adj = qMax(rational(0), range.in()); + rational end_range_adj = qMin(GetSequenceLength(), range.out()); + + qDebug() << "Cache invalidated between" + << start_range_adj.toDouble() + << "and" + << end_range_adj.toDouble(); + + if (from) { + // Queue value update + qDebug() << " from" << from->parentNode()->id() << "::" << from->id(); + QueueValueUpdate(from); + } + + InvalidateCacheInternal(start_range_adj, end_range_adj, only_visible); +} + void RenderBackend::CopyNodeInputValue(NodeInput *input) { // Find our copy of this parameter @@ -446,8 +458,10 @@ const QVector &RenderBackend::threads() return threads_; } -void RenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range) +void RenderBackend::InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) { + Q_UNUSED(only_visible) + // Add the range to the list cache_queue_.InsertTimeRange(TimeRange(start_range, end_range)); @@ -459,6 +473,11 @@ void RenderBackend::CacheIDChangedEvent(const QString &id) Q_UNUSED(id) } +void RenderBackend::WorkerAboutToStartEvent(RenderWorker *worker) +{ + Q_UNUSED(worker) +} + void RenderBackend::InitWorkers() { for (int i=0;i(worker)-> + SetOperatingMode(static_cast(mode)); + } } VideoRenderFrameCache *VideoRenderBackend::frame_cache() @@ -201,9 +234,11 @@ QString VideoRenderBackend::GetCachedFrame(const rational &time) void VideoRenderBackend::UpdateLastRequestedTime(const rational &time) { - last_time_requested_ = time; + if (last_time_requested_ != time) { + last_time_requested_ = time; - Requeue(); + Requeue(); + } } NodeInput *VideoRenderBackend::GetDependentInput() diff --git a/app/render/backend/videorenderbackend.h b/app/render/backend/videorenderbackend.h index fe7bc6f1b..97b1f09f9 100644 --- a/app/render/backend/videorenderbackend.h +++ b/app/render/backend/videorenderbackend.h @@ -99,10 +99,12 @@ protected: virtual void ConnectWorkerToThis(RenderWorker* processor) override; - virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range) override; + virtual void InvalidateCacheInternal(const rational &start_range, const rational &end_range, bool only_visible) override; virtual void ParamsChangedEvent(){} + virtual void WorkerAboutToStartEvent(RenderWorker* worker) override; + VideoRenderWorker::OperatingMode operating_mode_; signals: @@ -135,6 +137,8 @@ private: bool pop_toggle_; + bool queue_is_visible_only_; + private slots: void ThreadCompletedDownload(NodeDependency dep, qint64 job_time, QByteArray hash); void ThreadSkippedFrame(NodeDependency dep, qint64 job_time, QByteArray hash); diff --git a/app/widget/slider/sliderlabel.cpp b/app/widget/slider/sliderlabel.cpp index a54a54cf0..aee4a8409 100644 --- a/app/widget/slider/sliderlabel.cpp +++ b/app/widget/slider/sliderlabel.cpp @@ -22,6 +22,11 @@ #include #include +#include + +#ifdef Q_OS_MAC +#include +#endif OLIVE_NAMESPACE_ENTER @@ -48,40 +53,51 @@ SliderLabel::SliderLabel(QWidget *parent) : setFocusPolicy(Qt::TabFocus); } -void SliderLabel::mousePressEvent(QMouseEvent *ev) +void SliderLabel::mousePressEvent(QMouseEvent *) { - QLabel::mousePressEvent(ev); + emit drag_start(); +#if defined(Q_OS_MAC) + CGAssociateMouseAndMouseCursorPosition(false); + CGDisplayHideCursor(kCGDirectMainDisplay); + CGGetLastMouseDelta(nullptr, nullptr); +#else drag_start_ = QCursor::pos(); static_cast(QApplication::instance())->setOverrideCursor(Qt::BlankCursor); - - emit drag_start(); +#endif } -void SliderLabel::mouseMoveEvent(QMouseEvent *ev) +void SliderLabel::mouseMoveEvent(QMouseEvent *) { - QLabel::mouseMoveEvent(ev); - - QPoint current_pos = QCursor::pos(); - - int x_mvmt = current_pos.x() - drag_start_.x(); - int y_mvmt = drag_start_.y() - current_pos.y(); - - emit dragged(x_mvmt + y_mvmt); + int32_t x_mvmt, y_mvmt; // Keep cursor in the same position +#if defined(Q_OS_MAC) + CGGetLastMouseDelta(&x_mvmt, &y_mvmt); +#else + QPoint current_pos = QCursor::pos(); + + x_mvmt = current_pos.x() - drag_start_.x(); + y_mvmt = drag_start_.y() - current_pos.y(); + QCursor::setPos(drag_start_); +#endif + + emit dragged(x_mvmt + y_mvmt); } -void SliderLabel::mouseReleaseEvent(QMouseEvent *ev) +void SliderLabel::mouseReleaseEvent(QMouseEvent *) { - QWidget::mouseReleaseEvent(ev); +#if defined(Q_OS_MAC) + CGAssociateMouseAndMouseCursorPosition(true); + CGDisplayShowCursor(kCGDirectMainDisplay); +#else + static_cast(QApplication::instance())->restoreOverrideCursor(); +#endif // Emit a clicked signal emit drag_stop(); - - static_cast(QApplication::instance())->restoreOverrideCursor(); } void SliderLabel::focusInEvent(QFocusEvent *event) diff --git a/app/widget/slider/sliderlabel.h b/app/widget/slider/sliderlabel.h index 92771e669..c83e86bfc 100644 --- a/app/widget/slider/sliderlabel.h +++ b/app/widget/slider/sliderlabel.h @@ -54,6 +54,8 @@ signals: private: QPoint drag_start_; + bool cancel_mm_event_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 8fd2bab3a..292d07cc0 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -105,6 +105,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, this, &ViewerWidget::RendererCachedTime); connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, ruler(), &TimeRuler::CacheTimeReady); connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler(), &TimeRuler::CacheInvalidatedRange); + connect(video_renderer_, &VideoRenderBackend::GeneratedFrame, this, &ViewerWidget::RendererGeneratedFrame); audio_renderer_ = new AudioBackend(this); waveform_view_->SetBackend(audio_renderer_); @@ -522,6 +523,13 @@ void ViewerWidget::ContextMenuScopeTriggered(QAction *action) emit RequestScopePanel(static_cast(action->data().toInt())); } +void ViewerWidget::RendererGeneratedFrame(FramePtr f) +{ + foreach (ViewerDisplayWidget* glw, gl_widgets_) { + glw->SetImageFromLoadBuffer(f.get()); + } +} + void ViewerWidget::UpdateRendererParameters() { if (!GetConnectedNode()) { @@ -878,7 +886,7 @@ void ViewerWidget::SetZoomFromMenu(QAction *action) void ViewerWidget::InvalidateVisible(NodeInput* source) { - video_renderer_->InvalidateCache(TimeRange(GetTime(), GetTime()), source); + video_renderer_->InvalidateVisible(TimeRange(GetTime(), GetTime()), source); } OLIVE_NAMESPACE_EXIT diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 6d22e89a8..afeeaadd0 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -236,6 +236,8 @@ private slots: void ContextMenuScopeTriggered(QAction* action); + void RendererGeneratedFrame(FramePtr f); + }; OLIVE_NAMESPACE_EXIT