Merge branch 'master' into hashremoval

This commit is contained in:
itsmattkc
2022-05-16 09:12:49 -07:00
969 changed files with 4837 additions and 2393 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2021 Olive Team
# Copyright (C) 2022 Olive Team
#
# 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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+2 -2
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
@@ -87,7 +87,7 @@ void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enabl
if (!streams.isEmpty()) {
data_stream << streams << reinterpret_cast<quintptr>(GetConnectedNode());
mimedata->setData(QStringLiteral("application/x-oliveprojectitemdata"), encoded_data);
mimedata->setData(Project::kItemMimeType, encoded_data);
drag->setMimeData(mimedata);
drag->exec();
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+79 -12
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
@@ -37,12 +37,15 @@
#include "common/timecodefunctions.h"
#include "config/config.h"
#include "core.h"
#include "node/block/gap/gap.h"
#include "node/generator/shape/shapenodebase.h"
#include "node/project/project.h"
#include "render/rendermanager.h"
#include "task/taskmanager.h"
#include "viewerpreventsleep.h"
#include "widget/menu/menu.h"
#include "window/mainwindow/mainwindow.h"
#include "widget/timelinewidget/tool/add.h"
#include "widget/timeruler/timeruler.h"
namespace olive {
@@ -92,7 +95,9 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered);
connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped);
connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged);
connect(display_widget_, &ViewerDisplayWidget::QueueStarved, this, &ViewerWidget::ForceRequeueFromCurrentTime);
connect(display_widget_, &ViewerDisplayWidget::QueueStarved, this, &ViewerWidget::QueueStarved);
connect(display_widget_, &ViewerDisplayWidget::QueueNoLongerStarved, this, &ViewerWidget::QueueNoLongerStarved);
connect(display_widget_, &ViewerDisplayWidget::CreateAddableAt, this, &ViewerWidget::CreateAddableAt);
connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom);
connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate);
connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove);
@@ -476,6 +481,48 @@ void ViewerWidget::UpdateAudioProcessor()
}
}
void ViewerWidget::CreateAddableAt(const QRectF &f)
{
if (Sequence *s = dynamic_cast<Sequence*>(GetConnectedNode())) {
Track::Type type = Track::kVideo;
int track_index = -1;
TrackList *list = s->track_list(type);
const rational &in = GetTime();
rational length = OLIVE_CONFIG("DefaultStillLength").value<rational>();
rational out = in + length;
// Find a free track where we won't overwrite anything
while (true) {
track_index++;
if (track_index >= list->GetTrackCount()) {
// Just create a new track
break;
}
Track *track = list->GetTrackAt(track_index);
if (track->IsLocked()) {
continue;
}
Block *b = track->NearestBlockBeforeOrAt(in);
if (!b || (dynamic_cast<GapBlock*>(b) && b->out() >= out)) {
break;
}
}
MultiUndoCommand *command = new MultiUndoCommand();
Node *clip = AddTool::CreateAddableClip(command, s, Track::Reference(type, track_index), in, length);
if (ShapeNodeBase *shape = dynamic_cast<ShapeNodeBase*>(clip)) {
shape->SetRect(f, s->GetVideoParams(), command);
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
SetGizmos(clip);
}
}
void ViewerWidget::CloseAudioProcessor()
{
audio_processor_.Close();
@@ -499,7 +546,7 @@ void ViewerWidget::QueueNextAudioBuffer()
RenderTicketWatcher *watcher = new RenderTicketWatcher(this);
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForPlayback);
audio_playback_queue_.push_back(watcher);
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end), true));
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end), RenderTicketPriority::kHigh));
audio_playback_queue_time_ = queue_end;
}
@@ -590,6 +637,24 @@ void ViewerWidget::ReceivedAudioBufferForScrubbing()
delete watcher;
}
void ViewerWidget::QueueStarved()
{
static const int kMaximumWaitTime = 250;
qint64 now = QDateTime::currentMSecsSinceEpoch();
if (!queue_starved_start_) {
queue_starved_start_ = now;
} else if (now > queue_starved_start_ + kMaximumWaitTime) {
ForceRequeueFromCurrentTime();
queue_starved_start_ = 0;
}
}
void ViewerWidget::QueueNoLongerStarved()
{
queue_starved_start_ = 0;
}
void ViewerWidget::ForceRequeueFromCurrentTime()
{
ClearVideoAutoCacherQueue();
@@ -629,7 +694,7 @@ void ViewerWidget::UpdateTextureFromNode()
ClearVideoAutoCacherQueue();
}
watcher->SetTicket(GetFrame(time, true));
watcher->SetTicket(GetFrame(time, RenderTicketPriority::kHigh));
} else {
// There is definitely no frame here, we can immediately flip to showing nothing
nonqueue_watchers_.clear();
@@ -686,6 +751,8 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
controls_->ShowPauseButton();
queue_starved_start_ = 0;
// Attempt to fill playback queue
if (display_widget_->isVisible() || !windows_.isEmpty()) {
prequeue_length_ = DeterminePlaybackQueueSize();
@@ -702,7 +769,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
for (int i=0; i<prequeue_length_; i++) {
playback_queue_next_frame_ -= playback_speed_;
RequestNextFrameForQueue(true, false);
RequestNextFrameForQueue(RenderTicketPriority::kHigh, false);
}
playback_queue_next_frame_ = temp;
@@ -786,7 +853,7 @@ void ViewerWidget::PushScrubbedAudio()
RenderTicketWatcher *watcher = new RenderTicketWatcher();
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForScrubbing);
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval), true));
watcher->SetTicket(auto_cacher_.GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval), RenderTicketPriority::kHigh));
}
}
}
@@ -836,7 +903,7 @@ void ViewerWidget::SetDisplayImage(QVariant frame)
}
}
void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
void ViewerWidget::RequestNextFrameForQueue(RenderTicketPriority priority, bool increment)
{
rational next_time = Timecode::timestamp_to_time(playback_queue_next_frame_,
timebase());
@@ -850,17 +917,17 @@ void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
watcher->setProperty("time", QVariant::fromValue(next_time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
queue_watchers_.append(watcher);
watcher->SetTicket(GetFrame(next_time, prioritize));
watcher->SetTicket(GetFrame(next_time, priority));
}
}
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool prioritize)
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, RenderTicketPriority priority)
{
QString cache_fn = GetConnectedNode()->video_frame_cache()->CachePathName(t);
if (!QFileInfo::exists(cache_fn)) {
// Frame hasn't been cached, start render job
return auto_cacher_.GetSingleFrame(t, prioritize);
return auto_cacher_.GetSingleFrame(t, priority);
} else {
// Frame has been cached, grab the frame
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
@@ -1508,14 +1575,14 @@ void ViewerWidget::ViewerShiftedRange(const rational &from, const rational &to)
void ViewerWidget::DragEntered(QDragEnterEvent* event)
{
if (event->mimeData()->formats().contains(QStringLiteral("application/x-oliveprojectitemdata"))) {
if (event->mimeData()->formats().contains(Project::kItemMimeType)) {
event->accept();
}
}
void ViewerWidget::Dropped(QDropEvent *event)
{
QByteArray mimedata = event->mimeData()->data(QStringLiteral("application/x-oliveprojectitemdata"));
QByteArray mimedata = event->mimeData()->data(Project::kItemMimeType);
QDataStream stream(&mimedata, QIODevice::ReadOnly);
// Variables to deserialize into
+15 -3
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
@@ -119,6 +119,11 @@ public slots:
void UpdateTextureFromNode();
void RequestStartEditingText()
{
display_widget_->RequestStartEditingText();
}
signals:
/**
* @brief Wrapper for ViewerGLWidget::CursorColor()
@@ -185,9 +190,9 @@ private:
void SetDisplayImage(QVariant frame);
void RequestNextFrameForQueue(bool prioritize = false, bool increment = true);
void RequestNextFrameForQueue(RenderTicketPriority priority = RenderTicketPriority::kNormal, bool increment = true);
RenderTicketPtr GetFrame(const rational& t, bool prioritize);
RenderTicketPtr GetFrame(const rational& t, RenderTicketPriority priority);
void FinishPlayPreprocess();
@@ -269,6 +274,8 @@ private:
Track::Reference recording_track_;
QString recording_filename_;
qint64 queue_starved_start_;
private slots:
void PlaybackTimerUpdate();
@@ -316,10 +323,15 @@ private slots:
void ReceivedAudioBufferForScrubbing();
void QueueStarved();
void QueueNoLongerStarved();
void ForceRequeueFromCurrentTime();
void UpdateAudioProcessor();
void CreateAddableAt(const QRectF &f);
};
}
+152 -63
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
@@ -45,8 +45,6 @@
#include "node/gizmo/point.h"
#include "node/gizmo/polygon.h"
#include "node/gizmo/screen.h"
#include "node/gizmo/text.h"
#include "node/traverser.h"
#include "viewertexteditor.h"
#include "window/mainwindow/mainwindow.h"
@@ -68,9 +66,11 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
show_fps_(false),
frames_skipped_(0),
show_widget_background_(false),
push_mode_(kPushNull)
push_mode_(kPushNull),
add_band_(nullptr),
queue_starved_(false)
{
connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::UpdateCursor);
connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged);
connect(this, &ViewerDisplayWidget::InnerWidgetMouseMove, this, &ViewerDisplayWidget::EmitColorAtCursor);
@@ -106,6 +106,8 @@ void ViewerDisplayWidget::UpdateCursor()
{
if (Core::instance()->tool() == Tool::kHand) {
setCursor(Qt::OpenHandCursor);
} else if (Core::instance()->tool() == Tool::kAdd) {
setCursor(Qt::CrossCursor);
} else {
unsetCursor();
}
@@ -137,6 +139,11 @@ void ViewerDisplayWidget::SetBlank()
update();
}
void ViewerDisplayWidget::ToolChanged()
{
UpdateCursor();
}
void ViewerDisplayWidget::SetDeinterlacing(bool e)
{
deinterlace_ = e;
@@ -214,7 +221,7 @@ QPointF ViewerDisplayWidget::TransformViewerSpaceToBufferSpace(const QPointF &po
* Inversion will only fail if the viewer has been scaled by 0 in any direction
* which I think should never happen.
*/
return pos * GenerateGizmoTransform().inverted();
return pos * GenerateDisplayTransform().inverted();
}
void ViewerDisplayWidget::ResetFPSTimer()
@@ -236,8 +243,18 @@ void ViewerDisplayWidget::IncrementSkippedFrames()
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && gizmos_
&& (current_gizmo_ = TryGizmoPress(gizmo_db_, TransformViewerSpaceToBufferSpace(event->pos())))) {
if (event->button() == Qt::LeftButton && Core::instance()->tool() == Tool::kAdd
&& (Core::instance()->GetSelectedAddableObject() == Tool::kAddableShape || Core::instance()->GetSelectedAddableObject() == Tool::kAddableTitle)) {
add_band_start_ = event->pos();
add_band_ = new QRubberBand(QRubberBand::Rectangle, this);
add_band_->setGeometry(QRect(add_band_start_, add_band_start_));
add_band_->show();
} else if (event->button() == Qt::LeftButton && gizmos_
&& (gizmo_last_draw_transform_inverted_ = gizmo_last_draw_transform_.inverted(),
current_gizmo_ = TryGizmoPress(gizmo_db_, gizmo_last_draw_transform_inverted_.map(event->pos())))) {
// Handle gizmo click
gizmo_start_drag_ = event->pos();
@@ -275,12 +292,16 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
hand_last_drag_pos_ = event->pos();
} else if (add_band_) {
add_band_->setGeometry(QRect(event->pos(), add_band_start_).normalized());
} else if (current_gizmo_) {
// Signal movement
if (DraggableGizmo *draggable = dynamic_cast<DraggableGizmo*>(current_gizmo_)) {
if (!gizmo_drag_started_) {
QPointF start = TransformViewerSpaceToBufferSpace(gizmo_start_drag_);
QPointF start = gizmo_start_drag_ * gizmo_last_draw_transform_inverted_;
rational gizmo_time = GetGizmoTime();
NodeTraverser t;
@@ -291,17 +312,17 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
gizmo_drag_started_ = true;
}
QPointF v = TransformViewerSpaceToBufferSpace(event->pos());
QPointF v = event->pos() * gizmo_last_draw_transform_inverted_;
switch (draggable->GetDragValueBehavior()) {
case DraggableGizmo::kAbsolute:
// Above value is correct
break;
case DraggableGizmo::kDeltaFromPrevious:
v -= TransformViewerSpaceToBufferSpace(gizmo_last_drag_);
v -= gizmo_last_drag_ * gizmo_last_draw_transform_inverted_;
gizmo_last_drag_ = event->pos();
break;
case DraggableGizmo::kDeltaFromStart:
v -= TransformViewerSpaceToBufferSpace(gizmo_start_drag_);
v -= gizmo_start_drag_ * gizmo_last_draw_transform_inverted_;
break;
}
@@ -325,6 +346,17 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event)
hand_dragging_ = false;
UpdateCursor();
} else if (add_band_) {
const QRect &band_rect = add_band_->geometry();
if (band_rect.width() > 1 && band_rect.height() > 1) {
QRectF r = GenerateDisplayTransform().inverted().mapRect(add_band_->geometry());
emit CreateAddableAt(r);
}
add_band_->deleteLater();
add_band_ = nullptr;
} else if (current_gizmo_) {
// Handle gizmo
@@ -353,53 +385,7 @@ void ViewerDisplayWidget::mouseDoubleClickEvent(QMouseEvent *event)
foreach (NodeGizmo *g, gizmos_->GetGizmos()) {
if (TextGizmo *text = dynamic_cast<TextGizmo*>(g)) {
if (text->GetRect().contains(ptr)) {
QTransform gizmo_transform = GenerateGizmoTransform();
ViewerTextEditor *text_edit = new ViewerTextEditor(gizmo_transform.m11(), this);
Html::HtmlToDoc(text_edit->document(), text->GetHtml());
text_edit->setProperty("gizmo", reinterpret_cast<quintptr>(text));
QRectF transformed_geom = gizmo_transform.map(text->GetRect()).boundingRect();
text_edit->setGeometry(transformed_geom.toRect());
ViewerTextEditorToolBar *toolbar = new ViewerTextEditorToolBar(this);
QPoint pos = mapToGlobal(QPoint(transformed_geom.x(), transformed_geom.y() - toolbar->height()));
for (QScreen *screen : qApp->screens()) {
if (screen->geometry().contains(pos)) {
if (pos.x() + toolbar->width() > screen->geometry().right()) {
pos.setX(screen->geometry().right() - toolbar->width());
}
break;
}
}
toolbar->move(pos);
toolbar->show();
text_edit->show();
connect(text_edit, &ViewerTextEditor::textChanged, this, &ViewerDisplayWidget::TextEditChanged);
text_edit->ConnectToolBar(toolbar);
QPoint text_edit_pos = text_edit->mapFrom(this, event->pos());
// Ensure text edit is actually focused rather than the toolbar
connect(toolbar, &ViewerTextEditorToolBar::FirstPaint, this, [this, text_edit, text_edit_pos]{
// Grab focus back from the toolbar
this->raise();
this->activateWindow();
text_edit->setFocus();
// Start text cursor where the user clicked
text_edit->setTextCursor(text_edit->cursorForPosition(text_edit_pos));
// HACK: On macOS, for some reason the QDockWidget receives focus before the
// ViewerTextEditor, causing the editor to close prematurely. However this only
// happens the first time the editor receives focus and not subsequent times, so
// if we get it to only listen after the first one, this solves the problem.
text_edit->SetListenToFocusEvents(true);
});
OpenTextGizmo(text, event);
break;
}
}
@@ -525,7 +511,8 @@ void ViewerDisplayWidget::OnPaint()
gizmo_db_ = gt.GenerateRow(gizmos_, range);
QPainter p(inner_widget());
p.setWorldTransform(GenerateGizmoTransform());
gizmo_last_draw_transform_ = GenerateGizmoTransform(gt, range);
p.setWorldTransform(gizmo_last_draw_transform_);
gizmos_->UpdateGizmoPositions(gizmo_db_, NodeTraverser::GenerateGlobals(gizmo_params_, range));
foreach (NodeGizmo *gizmo, gizmos_->GetGizmos()) {
@@ -737,7 +724,7 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform()
return world;
}
QTransform ViewerDisplayWidget::GenerateGizmoTransform()
QTransform ViewerDisplayWidget::GenerateDisplayTransform()
{
QVector2D viewer_scale(GetTexturePosition(size()));
QTransform gizmo_transform = GenerateWorldTransform();
@@ -746,13 +733,39 @@ QTransform ViewerDisplayWidget::GenerateGizmoTransform()
return gizmo_transform;
}
QTransform ViewerDisplayWidget::GenerateGizmoTransform(NodeTraverser &gt, const TimeRange &range)
{
QTransform t = GenerateDisplayTransform();
if (GetTimeTarget()) {
Node *target = GetTimeTarget();
if (ViewerOutput *v = dynamic_cast<ViewerOutput *>(target)) {
if (Node *n = v->GetConnectedTextureOutput()) {
target = n;
}
}
QTransform nt;
gt.Transform(&nt, gizmos_, target, range);
t.translate(gizmo_params_.width()*0.5, gizmo_params_.height()*0.5);
t.scale(gizmo_params_.width(), gizmo_params_.height());
t = nt * t;
t.scale(1.0 / gizmo_params_.width(), 1.0 / gizmo_params_.height());
t.translate(-gizmo_params_.width()*0.5, -gizmo_params_.height()*0.5);
}
return t;
}
NodeGizmo *ViewerDisplayWidget::TryGizmoPress(const NodeValueRow &row, const QPointF &p)
{
for (auto it=gizmos_->GetGizmos().crbegin(); it!=gizmos_->GetGizmos().crend(); it++) {
NodeGizmo *gizmo = *it;
if (gizmo->IsVisible()) {
if (PointGizmo *point = dynamic_cast<PointGizmo*>(gizmo)) {
if (point->GetClickingRect(GenerateGizmoTransform()).contains(p)) {
if (point->GetClickingRect(gizmo_last_draw_transform_).contains(p)) {
return point;
}
} else if (PolygonGizmo *poly = dynamic_cast<PolygonGizmo*>(gizmo)) {
@@ -773,6 +786,62 @@ NodeGizmo *ViewerDisplayWidget::TryGizmoPress(const NodeValueRow &row, const QPo
return nullptr;
}
void ViewerDisplayWidget::OpenTextGizmo(TextGizmo *text, QMouseEvent *event)
{
QTransform gizmo_transform = GenerateDisplayTransform();
ViewerTextEditor *text_edit = new ViewerTextEditor(gizmo_transform.m11(), this);
Html::HtmlToDoc(text_edit->document(), text->GetHtml());
text_edit->setProperty("gizmo", reinterpret_cast<quintptr>(text));
QRectF transformed_geom = gizmo_transform.map(text->GetRect()).boundingRect();
text_edit->setGeometry(transformed_geom.toRect());
ViewerTextEditorToolBar *toolbar = new ViewerTextEditorToolBar(this);
QPoint pos = mapToGlobal(QPoint(transformed_geom.x(), transformed_geom.y() - toolbar->height()));
for (QScreen *screen : qApp->screens()) {
if (screen->geometry().contains(pos)) {
if (pos.x() + toolbar->width() > screen->geometry().right()) {
pos.setX(screen->geometry().right() - toolbar->width());
}
break;
}
}
toolbar->move(pos);
toolbar->show();
text_edit->show();
connect(text_edit, &ViewerTextEditor::textChanged, this, &ViewerDisplayWidget::TextEditChanged);
text_edit->ConnectToolBar(toolbar);
QPoint text_edit_pos;
if (event) {
text_edit_pos = text_edit->mapFrom(this, event->pos());
}
// Ensure text edit is actually focused rather than the toolbar
connect(toolbar, &ViewerTextEditorToolBar::FirstPaint, this, [this, text_edit, text_edit_pos]{
// Grab focus back from the toolbar
this->raise();
this->activateWindow();
text_edit->setFocus();
// Start text cursor where the user clicked
if (!text_edit_pos.isNull()) {
text_edit->setTextCursor(text_edit->cursorForPosition(text_edit_pos));
}
// HACK: On macOS, for some reason the QDockWidget receives focus before the
// ViewerTextEditor, causing the editor to close prematurely. However this only
// happens the first time the editor receives focus and not subsequent times, so
// if we get it to only listen after the first one, this solves the problem.
text_edit->SetListenToFocusEvents(true);
});
}
void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e)
{
// Do this no matter what, emits signal to any pixel samplers
@@ -780,7 +849,7 @@ void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e)
Color reference, display;
if (texture_) {
QPointF pixel_pos = GenerateGizmoTransform().inverted().map(e->pos());
QPointF pixel_pos = GenerateDisplayTransform().inverted().map(e->pos());
pixel_pos /= texture_->params().divider();
reference = renderer()->GetPixelFromTexture(texture_.get(), pixel_pos);
@@ -798,6 +867,18 @@ void ViewerDisplayWidget::SetShowFPS(bool e)
update();
}
void ViewerDisplayWidget::RequestStartEditingText()
{
if (gizmos_) {
foreach (NodeGizmo *gizmo, gizmos_->GetGizmos()) {
if (TextGizmo *text = dynamic_cast<TextGizmo*>(gizmo)) {
OpenTextGizmo(text);
break;
}
}
}
}
void ViewerDisplayWidget::Play(const int64_t &start_timestamp, const int &playback_speed, const rational &timebase)
{
playback_timebase_ = timebase;
@@ -814,6 +895,7 @@ void ViewerDisplayWidget::Pause()
disconnect(this, &ViewerDisplayWidget::frameSwapped, this, &ViewerDisplayWidget::UpdateFromQueue);
queue_.clear();
queue_starved_ = false;
}
void ViewerDisplayWidget::UpdateFromQueue()
@@ -825,6 +907,7 @@ void ViewerDisplayWidget::UpdateFromQueue()
bool popped = false;
if (queue_.empty()) {
queue_starved_ = true;
emit QueueStarved();
} else {
while (!queue_.empty()) {
@@ -834,6 +917,11 @@ void ViewerDisplayWidget::UpdateFromQueue()
// Frame was in queue, no need to decode anything
SetImage(pf.frame);
if (queue_starved_) {
queue_starved_ = false;
emit QueueNoLongerStarved();
}
return;
} else if (pf.timestamp > time) {
@@ -856,6 +944,7 @@ void ViewerDisplayWidget::UpdateFromQueue()
}
if (queue_.empty()) {
queue_starved_ = true;
emit QueueStarved();
break;
}
+26 -3
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
@@ -21,12 +21,15 @@
#ifndef VIEWERGLWIDGET_H
#define VIEWERGLWIDGET_H
#include <QOpenGLWidget>
#include <QMatrix4x4>
#include <QOpenGLWidget>
#include <QRubberBand>
#include "node/color/colormanager/colormanager.h"
#include "node/gizmo/text.h"
#include "node/node.h"
#include "node/output/track/tracklist.h"
#include "node/traverser.h"
#include "render/color.h"
#include "tool/tool.h"
#include "viewerplaybacktimer.h"
@@ -162,6 +165,8 @@ public slots:
*/
void UpdateCursor();
void ToolChanged();
/**
* @brief Enables/disables a basic deinterlace on the viewer
*/
@@ -169,6 +174,8 @@ public slots:
void SetShowFPS(bool e);
void RequestStartEditingText();
signals:
/**
* @brief Signal emitted when the user starts dragging from the viewer
@@ -205,6 +212,10 @@ signals:
void QueueStarved();
void QueueNoLongerStarved();
void CreateAddableAt(const QRectF &rect);
protected:
/**
* @brief Override the mouse press event for the DragStarted() signal and gizmos
@@ -254,7 +265,9 @@ private:
QTransform GenerateWorldTransform();
QTransform GenerateGizmoTransform();
QTransform GenerateDisplayTransform();
QTransform GenerateGizmoTransform(NodeTraverser &gt, const TimeRange &range);
TimeRange GenerateGizmoTime()
{
@@ -264,6 +277,8 @@ private:
NodeGizmo *TryGizmoPress(const NodeValueRow &row, const QPointF &p);
void OpenTextGizmo(TextGizmo *text, QMouseEvent *event = nullptr);
/**
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
*/
@@ -316,6 +331,8 @@ private:
QPoint gizmo_last_drag_;
NodeGizmo *current_gizmo_;
bool gizmo_drag_started_;
QTransform gizmo_last_draw_transform_;
QTransform gizmo_last_draw_transform_inverted_;
bool show_subtitles_;
Sequence *subtitle_tracks_;
@@ -366,6 +383,11 @@ private:
rational playback_timebase_;
QRubberBand *add_band_;
QPoint add_band_start_;
bool queue_starved_;
private slots:
void EmitColorAtCursor(QMouseEvent* e);
@@ -375,6 +397,7 @@ private slots:
void SubtitlesChanged(const TimeRange &r);
};
}
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+3 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
@@ -64,6 +64,8 @@ ViewerTextEditor::ViewerTextEditor(double scale, QWidget *parent) :
connect(qApp, &QApplication::focusChanged, this, &ViewerTextEditor::FocusChanged);
connect(this, &QTextEdit::currentCharFormatChanged, this, &ViewerTextEditor::FormatChanged);
connect(document(), &QTextDocument::contentsChanged, this, &ViewerTextEditor::DocumentChanged, Qt::QueuedConnection);
setAcceptRichText(false);
}
void ViewerTextEditor::ConnectToolBar(ViewerTextEditorToolBar *toolbar)
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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
+1 -1
View File
@@ -1,7 +1,7 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
Copyright (C) 2022 Olive Team
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