Merge branch 'master' into cache-update

This commit is contained in:
itsmattkc
2022-07-01 22:32:49 -05:00
98 changed files with 1638 additions and 1480 deletions
+9 -6
View File
@@ -20,6 +20,7 @@
#include "audiomonitor.h"
#include <QApplication>
#include <QDebug>
#include <QPainter>
@@ -35,8 +36,7 @@ const int kMaximumSmoothness = 8;
QVector<AudioMonitor*> AudioMonitor::instances_;
AudioMonitor::AudioMonitor(QWidget *parent) :
QOpenGLWidget(parent),
AudioMonitor::AudioMonitor() :
waveform_(nullptr),
cached_channels_(0)
{
@@ -126,7 +126,10 @@ void AudioMonitor::SetUpdateLoop(bool e)
void AudioMonitor::paintGL()
{
QPainter p(this);
p.fillRect(rect(), palette().window().color());
QPalette palette = qApp->palette();
QRect geometry(0, 0, width(), height());
p.fillRect(geometry, palette.window().color());
if (!params_.channel_count()) {
return;
@@ -138,12 +141,12 @@ void AudioMonitor::paintGL()
int font_height = fm.height();
// Create rect where decibel markings will go on the side
QRect db_labels_rect = rect();
QRect db_labels_rect = geometry;
db_labels_rect.setWidth(QtUtils::QFontMetricsWidth(p.fontMetrics(), "-00"));
db_labels_rect.adjust(0, font_height, 0, 0);
// Determine rect where the main meter will go
QRect full_meter_rect = rect();
QRect full_meter_rect = geometry;
full_meter_rect.adjust(db_labels_rect.width(), font_height, 0, 0);
// Width of each channel in the meter
@@ -164,7 +167,7 @@ void AudioMonitor::paintGL()
// Draw decibel markings
QRect last_db_marking_rect;
cached_painter.setPen(palette().text().color());
cached_painter.setPen(palette.text().color());
for (int i=0;i>=kDecibelMinimum;i-=kDecibelStep) {
QString db_label;
+3 -3
View File
@@ -22,7 +22,7 @@
#define AUDIOMONITORWIDGET_H
#include <QFile>
#include <QOpenGLWidget>
#include <QOpenGLWindow>
#include <QTimer>
#include "audio/audiovisualwaveform.h"
@@ -32,11 +32,11 @@
namespace olive {
class AudioMonitor : public QOpenGLWidget
class AudioMonitor : public QOpenGLWindow
{
Q_OBJECT
public:
AudioMonitor(QWidget* parent = nullptr);
AudioMonitor();
virtual ~AudioMonitor() override;
+61 -7
View File
@@ -23,18 +23,19 @@
#include <QHBoxLayout>
#include <QMessageBox>
#include "panel/panelmanager.h"
#include "render/opengl/openglrenderer.h"
#include "render/rendermanager.h"
namespace olive {
#define super QWidget
ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
QWidget(parent),
color_manager_(nullptr),
color_service_(nullptr)
{
setContextMenuPolicy(Qt::CustomContextMenu);
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setSpacing(0);
layout->setMargin(0);
@@ -55,17 +56,18 @@ ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) :
&ManagedDisplayWidgetOpenGL::frameSwapped,
this, &ManagedDisplayWidget::frameSwapped, Qt::DirectConnection);
connect(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_),
&ManagedDisplayWidgetOpenGL::OnMouseMove,
this, &ManagedDisplayWidget::InnerWidgetMouseMove);
inner_widget_->installEventFilter(this);
// Create OpenGL renderer
attached_renderer_ = new OpenGLRenderer(this);
// Create widget wrapper for OpenGL window
wrapper_ = QWidget::createWindowContainer(static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_));
layout->addWidget(wrapper_);
} else {
inner_widget_ = nullptr;
wrapper_ = nullptr;
}
layout->addWidget(inner_widget_);
}
ManagedDisplayWidget::~ManagedDisplayWidget()
@@ -253,6 +255,22 @@ void ManagedDisplayWidget::doneCurrent()
}
}
QPaintDevice *ManagedDisplayWidget::paint_device() const
{
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
return static_cast<ManagedDisplayWidgetOpenGL*>(inner_widget_);
} else {
return nullptr;
}
}
void ManagedDisplayWidget::SetInnerMouseTracking(bool e)
{
if (wrapper_) {
wrapper_->setMouseTracking(e);
}
}
void ManagedDisplayWidget::update()
{
if (RenderManager::instance()->backend() == RenderManager::kOpenGL) {
@@ -260,6 +278,42 @@ void ManagedDisplayWidget::update()
}
}
bool ManagedDisplayWidget::eventFilter(QObject *o, QEvent *e)
{
if (o != inner_widget_) {
return super::eventFilter(o, e);
}
switch (e->type()) {
case QEvent::FocusIn:
// HACK: QWindow focus isn't accounted for in QApplication::focusChanged, so we handle it
// manually here.
PanelManager::instance()->FocusChanged(nullptr, this);
break;
case QEvent::ContextMenu:
{
QContextMenuEvent *ctx = static_cast<QContextMenuEvent*>(e);
emit customContextMenuRequested(ctx->pos());
return true;
}
case QEvent::MouseButtonPress:
{
// HACK: QWindows don't seem to receive ContextMenu events on right click (only when pressing
// the menu button on the keyboard) so we handle it manually here
QMouseEvent *ev = static_cast<QMouseEvent*>(e);
if (ev->button() == Qt::RightButton) {
emit customContextMenuRequested(ev->pos());
return true;
}
break;
}
default:
break;
}
return super::eventFilter(o, e);
}
Menu* ManagedDisplayWidget::GetDisplayMenu(QMenu* parent, bool auto_connect)
{
QStringList displays = color_manager()->ListAvailableDisplays();
+24 -21
View File
@@ -23,7 +23,7 @@
#include <QMouseEvent>
#include <QOpenGLContext>
#include <QOpenGLWidget>
#include <QOpenGLWindow>
#include "node/color/colormanager/colormanager.h"
#include "render/renderer.h"
@@ -31,24 +31,18 @@
namespace olive {
class ManagedDisplayWidgetOpenGL : public QOpenGLWidget
class ManagedDisplayWidgetOpenGL : public QOpenGLWindow
{
Q_OBJECT
public:
ManagedDisplayWidgetOpenGL(QWidget* parent = nullptr) :
QOpenGLWidget(parent)
{
}
ManagedDisplayWidgetOpenGL() = default;
signals:
// Render signals
void OnInit();
void OnPaint();
void OnDestroy();
void OnMouseMove(QMouseEvent* e);
protected:
virtual void initializeGL() override
{
@@ -63,13 +57,6 @@ protected:
emit OnPaint();
}
virtual void mouseMoveEvent(QMouseEvent* e) override
{
emit OnMouseMove(e);
QOpenGLWidget::mouseMoveEvent(e);
}
private slots:
void DestroyListener()
{
@@ -135,6 +122,8 @@ public:
*/
void update();
virtual bool eventFilter(QObject *o, QEvent *e) override;
public slots:
/**
* @brief Replaces the color transform with a new one
@@ -159,8 +148,6 @@ signals:
void frameSwapped();
void InnerWidgetMouseMove(QMouseEvent* event);
protected:
/**
* @brief Provides access to the color processor (nullptr if none is set)
@@ -188,11 +175,26 @@ protected:
void doneCurrent();
QWidget* inner_widget() const
QWindow* inner_widget() const
{
return inner_widget_;
}
/**
* @brief Get inner widget as paint device for QPainter
*
* NOTE: This will be incompatible with QVulkanWindow so functions using it
* will need to be replaced soon.
*/
QPaintDevice *paint_device() const;
void SetInnerMouseTracking(bool e);
QRect GetInnerRect() const
{
return wrapper_ ? wrapper_->rect() : QRect();
}
protected slots:
/**
* @brief Called whenever the internal rendering context has been created
@@ -223,7 +225,8 @@ private:
/**
* @brief Main drawing surface abstraction
*/
QWidget* inner_widget_;
QWindow* inner_widget_;
QWidget *wrapper_;
/**
* @brief Renderer abstraction
+1 -1
View File
@@ -291,7 +291,7 @@ void MenuShared::NestTriggered()
void MenuShared::DefaultTransitionTriggered()
{
qDebug() << "FIXME: Stub";
PanelManager::instance()->MostRecentlyFocused<TimelinePanel>()->AddDefaultTransitionsToSelected();
}
void MenuShared::TimecodeDisplayTriggered()
@@ -84,6 +84,7 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) :
NodeParamViewItemTitleBar *title_bar = static_cast<NodeParamViewItemTitleBar*>(c->titleBarWidget());
if (i == Track::kVideo || i == Track::kAudio) {
c->SetEffectType(static_cast<Track::Type>(i));
title_bar->SetAddEffectButtonVisible(true);
title_bar->SetText(tr("%1 Nodes").arg(Footage::GetStreamTypeName(static_cast<Track::Type>(i))));
} else {
@@ -31,7 +31,8 @@ namespace olive {
#define super NodeParamViewItemBase
NodeParamViewContext::NodeParamViewContext(QWidget *parent) :
super(parent)
super(parent),
type_(Track::kNone)
{
QWidget *body = new QWidget();
QHBoxLayout *body_layout = new QHBoxLayout(body);
@@ -126,13 +127,30 @@ void NodeParamViewContext::SetTime(const rational &time)
}
}
void NodeParamViewContext::SetEffectType(Track::Type type)
{
type_ = type;
}
void NodeParamViewContext::Retranslate()
{
}
void NodeParamViewContext::AddEffectButtonClicked()
{
Menu *m = NodeFactory::CreateMenu(this, false, Node::kCategoryUnknown, Node::kVideoEffect);
Node::Flag flag = Node::kNone;
if (type_ == Track::kVideo) {
flag = Node::kVideoEffect;
} else {
flag = Node::kAudioEffect;
}
if (flag == Node::kNone) {
return;
}
Menu *m = NodeFactory::CreateMenu(this, false, Node::kCategoryUnknown, flag);
connect(m, &Menu::triggered, this, &NodeParamViewContext::AddEffectMenuItemTriggered);
m->exec(QCursor::pos());
delete m;
@@ -64,6 +64,8 @@ public:
void SetTime(const rational &time);
void SetEffectType(Track::Type type);
signals:
void AboutToDeleteItem(NodeParamViewItem *item);
@@ -88,6 +90,8 @@ private:
QVector<NodeParamViewItem*> items_;
Track::Type type_;
private slots:
void AddEffectButtonClicked();
@@ -23,6 +23,7 @@
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QFileDialog>
#include <QMessageBox>
#include <QProcess>
#include <QUrl>
@@ -37,6 +38,7 @@
#include "task/taskmanager.h"
#include "widget/menu/menu.h"
#include "widget/menu/menushared.h"
#include "widget/nodeparamview/nodeparamviewundo.h"
#include "window/mainwindow/mainwindow.h"
#include "window/mainwindow/mainwindowundo.h"
#include "widget/nodeview/nodeviewundo.h"
@@ -392,6 +394,9 @@ void ProjectExplorer::ShowContextMenu()
QAction* reveal_action = menu.addAction(reveal_text);
connect(reveal_action, &QAction::triggered, this, &ProjectExplorer::RevealSelectedFootage);
QAction *replace_action = menu.addAction(tr("Replace Footage"));
connect(replace_action, &QAction::triggered, this, &ProjectExplorer::ReplaceSelectedFootage);
}
menu.addSeparator();
@@ -497,6 +502,17 @@ void ProjectExplorer::RevealSelectedFootage()
#endif
}
void ProjectExplorer::ReplaceSelectedFootage()
{
Footage* footage = static_cast<Footage*>(context_menu_items_.first());
QString file = QFileDialog::getOpenFileName(this, tr("Replace Footage"));
if (!file.isEmpty()) {
auto c = new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(footage, Footage::kFilenameInput)), file);
Core::instance()->undo_stack()->push(c);
}
}
void ProjectExplorer::OpenContextMenuItemInNewTab()
{
Core::instance()->main_window()->FolderOpen(project(), static_cast<Folder*>(context_menu_items_.first()), false);
@@ -185,6 +185,8 @@ private slots:
void RevealSelectedFootage();
void ReplaceSelectedFootage();
void OpenContextMenuItemInNewTab();
void OpenContextMenuItemInNewWindow();
@@ -31,36 +31,51 @@ namespace olive {
ResizableTimelineScrollBar::ResizableTimelineScrollBar(QWidget* parent) :
ResizableScrollBar(parent),
points_(nullptr),
markers_(nullptr),
workarea_(nullptr),
scale_(1.0)
{
}
ResizableTimelineScrollBar::ResizableTimelineScrollBar(Qt::Orientation orientation, QWidget* parent) :
ResizableScrollBar(orientation, parent),
points_(nullptr),
markers_(nullptr),
workarea_(nullptr),
scale_(1.0)
{
}
void ResizableTimelineScrollBar::ConnectTimelinePoints(TimelinePoints *points)
void ResizableTimelineScrollBar::ConnectMarkers(TimelineMarkerList *markers)
{
if (points_) {
disconnect(points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(points_->markers(), &TimelineMarkerList::MarkerModified, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
if (markers_) {
disconnect(markers_, &TimelineMarkerList::MarkerAdded, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(markers_, &TimelineMarkerList::MarkerRemoved, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(markers_, &TimelineMarkerList::MarkerModified, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
}
points_ = points;
markers_ = markers;
if (points_) {
connect(points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(points_->markers(), &TimelineMarkerList::MarkerAdded, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(points_->markers(), &TimelineMarkerList::MarkerRemoved, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(points_->markers(), &TimelineMarkerList::MarkerModified, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
if (markers_) {
connect(markers_, &TimelineMarkerList::MarkerAdded, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(markers_, &TimelineMarkerList::MarkerRemoved, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(markers_, &TimelineMarkerList::MarkerModified, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
}
update();
}
void ResizableTimelineScrollBar::ConnectWorkArea(TimelineWorkArea *workarea)
{
if (workarea_) {
disconnect(workarea_, &TimelineWorkArea::RangeChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
disconnect(workarea_, &TimelineWorkArea::EnabledChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
}
workarea_ = workarea;
if (workarea_) {
connect(workarea_, &TimelineWorkArea::RangeChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
connect(workarea_, &TimelineWorkArea::EnabledChanged, this, static_cast<void (ResizableTimelineScrollBar::*)()>(&ResizableTimelineScrollBar::update));
}
update();
@@ -77,9 +92,8 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
{
ResizableScrollBar::paintEvent(event);
if (points_
&& !timebase().isNull()
&& (points_->workarea()->enabled() || !points_->markers()->empty())) {
if (!timebase().isNull() && ((workarea_ && workarea_->enabled()) || (markers_ && !markers_->empty()))) {
// Draw workarea
QStyleOptionSlider opt;
initStyleOption(&opt);
@@ -87,20 +101,20 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
QStyle::SC_ScrollBarGroove, this);
double ratio = scale_ * double(gr.width()) / double(this->maximum() + gr.width());
QPainter p(this);
if (points_->workarea()->enabled()) {
if (workarea_ && workarea_->enabled()) {
QColor workarea_color(this->palette().highlight().color());
workarea_color.setAlpha(128);
qint64 in = qMax(qint64(0), qRound64(ratio * TimeToScene(points_->workarea()->in())));
qint64 in = qMax(qint64(0), qRound64(ratio * TimeToScene(workarea_->in())));
qint64 out;
if (points_->workarea()->out() == RATIONAL_MAX) {
if (workarea_->out() == RATIONAL_MAX) {
out = gr.width();
} else {
out = qMin(qint64(gr.width()), qRound64(ratio * TimeToScene(points_->workarea()->out())));
out = qMin(qint64(gr.width()), qRound64(ratio * TimeToScene(workarea_->out())));
}
qint64 length = qMax(qint64(1), out-in);
@@ -112,8 +126,9 @@ void ResizableTimelineScrollBar::paintEvent(QPaintEvent *event)
workarea_color);
}
if (!points_->markers()->empty()) {
for (auto it=points_->markers()->cbegin(); it!=points_->markers()->cend(); it++) {
// Draw markers
if (markers_ && !markers_->empty()) {
for (auto it=markers_->cbegin(); it!=markers_->cend(); it++) {
TimelineMarker* marker = *it;
QColor marker_color = ColorCoding::GetColor(marker->color()).toQColor();
@@ -22,7 +22,8 @@
#define RESIZABLETIMELINESCROLLBAR_H
#include "resizablescrollbar.h"
#include "timeline/timelinepoints.h"
#include "timeline/timelinemarker.h"
#include "timeline/timelineworkarea.h"
#include "widget/timebased/timescaledobject.h"
namespace olive {
@@ -34,7 +35,8 @@ public:
ResizableTimelineScrollBar(QWidget* parent = nullptr);
ResizableTimelineScrollBar(Qt::Orientation orientation, QWidget* parent = nullptr);
void ConnectTimelinePoints(TimelinePoints* points);
void ConnectMarkers(TimelineMarkerList *markers);
void ConnectWorkArea(TimelineWorkArea *workarea);
void SetScale(double d);
@@ -42,7 +44,9 @@ protected:
virtual void paintEvent(QPaintEvent* event) override;
private:
TimelinePoints* points_;
TimelineMarkerList* markers_;
TimelineWorkArea* workarea_;
double scale_;
+1 -1
View File
@@ -91,7 +91,7 @@ void HistogramScope::DrawScope(TexturePtr managed_tex, QVariant pipeline)
renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params());
// Draw line overlays
QPainter p(inner_widget());
QPainter p(paint_device());
QFont font = p.font();
font.setPixelSize(10);
QFontMetrics font_metrics = QFontMetrics(font);
+1 -1
View File
@@ -85,7 +85,7 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline)
float waveform_end_dim_x = (width() - 1.0) - waveform_start_dim_x;
// Draw line overlays
QPainter p(inner_widget());
QPainter p(paint_device());
QFont font;
font.setPixelSize(10);
QFontMetrics font_metrics = QFontMetrics(font);
+1 -1
View File
@@ -120,7 +120,7 @@ void SliderLadder::SetValue(const QString &s)
void SliderLadder::StartListeningToMouseInput()
{
drag_timer_.start();
QMetaObject::invokeMethod(&drag_timer_, "start", Qt::QueuedConnection);
}
void SliderLadder::mouseReleaseEvent(QMouseEvent *event)
@@ -35,15 +35,7 @@ public:
QComboBox(parent)
{
foreach (int d, VideoParams::kSupportedDividers) {
QString name;
if (d == 1) {
name = tr("Full");
} else {
name = tr("1/%1").arg(d);
}
this->addItem(name, d);
this->addItem(VideoParams::GetNameForDivider(d), d);
}
}
+46 -31
View File
@@ -39,7 +39,9 @@ TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_statu
viewer_node_(nullptr),
auto_max_scrollbar_(false),
toggle_show_all_(false),
auto_set_timebase_(true)
auto_set_timebase_(true),
workarea_(nullptr),
markers_(nullptr)
{
ruler_ = new TimeRuler(ruler_text_visible, ruler_cache_status_visible, this);
ConnectTimelineView(ruler_, true);
@@ -98,8 +100,8 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node)
SetTimebase(rational());
// Disconnect ruler and scrollbar from timeline points
ruler()->ConnectTimelinePoints(nullptr);
scrollbar_->ConnectTimelinePoints(nullptr);
ConnectWorkArea(nullptr);
ConnectMarkers(nullptr);
}
// Call derivatives
@@ -111,8 +113,8 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node)
connect(viewer_node_, &ViewerOutput::RemovedFromGraph, this, &TimeBasedWidget::ConnectedNodeRemovedFromGraph);
// Connect ruler and scrollbar to timeline points
ruler()->ConnectTimelinePoints(viewer_node_->GetTimelinePoints());
scrollbar_->ConnectTimelinePoints(viewer_node_->GetTimelinePoints());
ConnectWorkArea(viewer_node_->GetWorkArea());
ConnectMarkers(viewer_node_->GetMarkers());
// If we're setting the timebase, set it automatically based on the video and audio parameters
if (auto_set_timebase_) {
@@ -130,6 +132,20 @@ void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node)
emit ConnectedNodeChanged(old, node);
}
void TimeBasedWidget::ConnectWorkArea(TimelineWorkArea *workarea)
{
workarea_ = workarea;
ruler()->SetWorkArea(workarea);
scrollbar_->ConnectWorkArea(workarea);
}
void TimeBasedWidget::ConnectMarkers(TimelineMarkerList *markers)
{
markers_ = markers;
ruler()->SetMarkers(markers);
scrollbar_->ConnectMarkers(markers);
}
void TimeBasedWidget::UpdateMaximumScroll()
{
rational length = (viewer_node_) ? viewer_node_->GetLength() : 0;
@@ -374,14 +390,14 @@ void TimeBasedWidget::GoToNextCut()
rational closest_cut = RATIONAL_MAX;
foreach (Track* track, sequence->GetTracks()) {
for (Track* track : sequence->GetTracks()) {
rational this_track_closest_cut = track->track_length();
if (this_track_closest_cut <= GetTime()) {
this_track_closest_cut = RATIONAL_MAX;
}
foreach (Block* block, track->Blocks()) {
for (Block* block : track->Blocks()) {
if (block->in() > GetTime()) {
this_track_closest_cut = block->in();
break;
@@ -457,10 +473,10 @@ void TimeBasedWidget::SetPoint(Timeline::MovementMode m, const rational& time)
}
MultiUndoCommand* command = new MultiUndoCommand();
TimelinePoints* points = viewer_node_->GetTimelinePoints();
TimelineWorkArea* points = viewer_node_->GetWorkArea();
// Enable workarea if it isn't already enabled
if (!points->workarea()->enabled()) {
if (!points->enabled()) {
command->add_child(new WorkareaSetEnabledCommand(viewer_node_->project(), points, true));
}
@@ -470,23 +486,23 @@ void TimeBasedWidget::SetPoint(Timeline::MovementMode m, const rational& time)
if (m == Timeline::kTrimIn) {
in_point = time;
if (!points->workarea()->enabled() || points->workarea()->out() < in_point) {
if (!points->enabled() || points->out() < in_point) {
out_point = TimelineWorkArea::kResetOut;
} else {
out_point = points->workarea()->out();
out_point = points->out();
}
} else {
out_point = time;
if (!points->workarea()->enabled() || points->workarea()->in() > out_point) {
if (!points->enabled() || points->in() > out_point) {
in_point = TimelineWorkArea::kResetIn;
} else {
in_point = points->workarea()->in();
in_point = points->in();
}
}
// Set workarea
command->add_child(new WorkareaSetRangeCommand(points->workarea(), TimeRange(in_point, out_point)));
command->add_child(new WorkareaSetRangeCommand(points, TimeRange(in_point, out_point)));
Core::instance()->undo_stack()->push(command);
}
@@ -497,13 +513,13 @@ void TimeBasedWidget::ResetPoint(Timeline::MovementMode m)
return;
}
TimelinePoints* points = GetConnectedNode()->GetTimelinePoints();
TimelineWorkArea* points = GetConnectedNode()->GetWorkArea();
if (!GetConnectedNode() || !points->workarea()->enabled()) {
if (!points->enabled()) {
return;
}
TimeRange r = points->workarea()->range();
TimeRange r = points->range();
if (m == Timeline::kTrimIn) {
r.set_in(TimelineWorkArea::kResetIn);
@@ -511,7 +527,7 @@ void TimeBasedWidget::ResetPoint(Timeline::MovementMode m)
r.set_out(TimelineWorkArea::kResetOut);
}
Core::instance()->undo_stack()->push(new WorkareaSetRangeCommand(points->workarea(), r));
Core::instance()->undo_stack()->push(new WorkareaSetRangeCommand(points, r));
}
void TimeBasedWidget::PageScrollInternal(QScrollBar *bar, int maximum, int screen_position, bool whole_page_scroll)
@@ -582,8 +598,7 @@ void TimeBasedWidget::ClearInOutPoints()
return;
}
Core::instance()->undo_stack()->push(new WorkareaSetEnabledCommand(GetConnectedNode()->project(), GetConnectedNode()->GetTimelinePoints(), false));
Core::instance()->undo_stack()->push(new WorkareaSetEnabledCommand(GetConnectedNode()->project(), GetConnectedNode()->GetWorkArea(), false));
}
void TimeBasedWidget::SetMarker()
@@ -592,7 +607,7 @@ void TimeBasedWidget::SetMarker()
return;
}
TimelineMarkerList *markers = GetConnectedNode()->GetTimelinePoints()->markers();
TimelineMarkerList *markers = GetConnectedNode()->GetMarkers();
if (TimelineMarker *existing = markers->GetMarkerAtTime(GetTime())) {
// We already have a marker here, so pop open the edit dialog
@@ -661,8 +676,8 @@ void TimeBasedWidget::ToggleShowAll()
void TimeBasedWidget::GoToIn()
{
if (GetConnectedNode()) {
if (GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
SetTimeAndSignal(GetConnectedNode()->GetTimelinePoints()->workarea()->in());
if (GetConnectedNode()->GetWorkArea()->enabled()) {
SetTimeAndSignal(GetConnectedNode()->GetWorkArea()->in());
} else {
GoToStart();
}
@@ -672,8 +687,8 @@ void TimeBasedWidget::GoToIn()
void TimeBasedWidget::GoToOut()
{
if (GetConnectedNode()) {
if (GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
SetTimeAndSignal(GetConnectedNode()->GetTimelinePoints()->workarea()->out());
if (GetConnectedNode()->GetWorkArea()->enabled()) {
SetTimeAndSignal(GetConnectedNode()->GetWorkArea()->out());
} else {
GoToEnd();
}
@@ -750,7 +765,7 @@ bool TimeBasedWidget::SnapPoint(const std::vector<rational> &start_times, ration
// Snap to clip markers too
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(b)) {
if (clip->connected_viewer()) {
TimelineMarkerList *markers = clip->connected_viewer()->GetTimelinePoints()->markers();
TimelineMarkerList *markers = clip->connected_viewer()->GetMarkers();
for (auto jt=markers->cbegin(); jt!=markers->cend(); jt++) {
TimelineMarker *marker = *jt;
@@ -768,8 +783,8 @@ bool TimeBasedWidget::SnapPoint(const std::vector<rational> &start_times, ration
}
}
if ((snap_points & kSnapToMarkers) && ruler()->GetTimelinePoints()) {
for (auto it=ruler()->GetTimelinePoints()->markers()->cbegin(); it!=ruler()->GetTimelinePoints()->markers()->cend(); it++) {
if ((snap_points & kSnapToMarkers) && ruler()->GetMarkers()) {
for (auto it=ruler()->GetMarkers()->cbegin(); it!=ruler()->GetMarkers()->cend(); it++) {
TimelineMarker* m = *it;
// Ignore selected markers
@@ -787,9 +802,9 @@ bool TimeBasedWidget::SnapPoint(const std::vector<rational> &start_times, ration
}
}
if ((snap_points & kSnapToWorkarea) && ruler()->GetTimelinePoints()) {
const rational &workarea_in = ruler()->GetTimelinePoints()->workarea()->in();
const rational &workarea_out = ruler()->GetTimelinePoints()->workarea()->out();
if ((snap_points & kSnapToWorkarea) && ruler()->GetWorkArea()) {
const rational &workarea_in = ruler()->GetWorkArea()->in();
const rational &workarea_out = ruler()->GetWorkArea()->out();
AttemptSnap(potential_snaps, screen_pt, TimeToScene(workarea_in), start_times, workarea_in);
AttemptSnap(potential_snaps, screen_pt, TimeToScene(workarea_out), start_times, workarea_out);
+11
View File
@@ -50,6 +50,11 @@ public:
void ConnectViewerNode(ViewerOutput *node);
TimelineWorkArea *GetConnectedWorkArea() const { return workarea_; }
TimelineMarkerList *GetConnectedMarkers() const { return markers_; }
void ConnectWorkArea(TimelineWorkArea *workarea);
void ConnectMarkers(TimelineMarkerList *markers);
void SetScaleAndCenterOnPlayhead(const double& scale);
TimeRuler* ruler() const;
@@ -130,6 +135,9 @@ protected:
virtual void ConnectedNodeChangeEvent(ViewerOutput*){}
virtual void ConnectedWorkAreaChangeEvent(TimelineWorkArea *){}
virtual void ConnectedMarkersChangeEvent(TimelineMarkerList *){}
virtual void ConnectNodeEvent(ViewerOutput*){}
virtual void DisconnectNodeEvent(ViewerOutput*){}
@@ -217,6 +225,9 @@ private:
double scrollbar_start_scale_;
bool scrollbar_top_handle_;
TimelineWorkArea *workarea_;
TimelineMarkerList *markers_;
private slots:
void UpdateMaximumScroll();
+38 -7
View File
@@ -569,6 +569,22 @@ void TimelineWidget::ToggleLinksOnSelected()
Core::instance()->undo_stack()->push(new NodeLinkManyCommand(blocks, link));
}
void TimelineWidget::AddDefaultTransitionsToSelected()
{
QVector<ClipBlock*> blocks;
foreach (Block* item, GetSelectedBlocks()) {
// Only clips can be linked
if (ClipBlock *clip = dynamic_cast<ClipBlock*>(item)) {
blocks.append(clip);
}
}
if (!blocks.isEmpty()) {
Core::instance()->undo_stack()->push(new TimelineAddDefaultTransitionCommand(blocks, timebase()));
}
}
bool TimelineWidget::CopySelected(bool cut)
{
if (super::CopySelected(cut)) {
@@ -639,7 +655,7 @@ void TimelineWidget::PasteInsert()
void TimelineWidget::DeleteInToOut(bool ripple)
{
if (!GetConnectedNode()
|| !GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
|| !GetConnectedNode()->GetWorkArea()->enabled()) {
return;
}
@@ -649,8 +665,8 @@ void TimelineWidget::DeleteInToOut(bool ripple)
command->add_child(new TimelineRippleRemoveAreaCommand(
sequence(),
GetConnectedNode()->GetTimelinePoints()->workarea()->in(),
GetConnectedNode()->GetTimelinePoints()->workarea()->out()));
GetConnectedNode()->GetWorkArea()->in(),
GetConnectedNode()->GetWorkArea()->out()));
} else {
QVector<Track*> unlocked_tracks = sequence()->GetUnlockedTracks();
@@ -658,7 +674,7 @@ void TimelineWidget::DeleteInToOut(bool ripple)
foreach (Track* track, unlocked_tracks) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(GetConnectedNode()->GetTimelinePoints()->workarea()->length());
gap->set_length_and_media_out(GetConnectedNode()->GetWorkArea()->length());
command->add_child(new NodeAddCommand(static_cast<NodeGraph*>(track->parent()),
gap));
@@ -666,17 +682,17 @@ void TimelineWidget::DeleteInToOut(bool ripple)
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track->type()),
track->Index(),
gap,
GetConnectedNode()->GetTimelinePoints()->workarea()->in()));
GetConnectedNode()->GetWorkArea()->in()));
}
}
// Clear workarea after this
command->add_child(new WorkareaSetEnabledCommand(GetConnectedNode()->project(),
GetConnectedNode()->GetTimelinePoints(),
GetConnectedNode()->GetWorkArea(),
false));
if (ripple) {
SetTimeAndSignal(GetConnectedNode()->GetTimelinePoints()->workarea()->in());
SetTimeAndSignal(GetConnectedNode()->GetWorkArea()->in());
}
Core::instance()->undo_stack()->push(command);
@@ -1079,6 +1095,11 @@ void TimelineWidget::ShowContextMenu()
connect(autocache_action, &QAction::triggered, this, &TimelineWidget::SetSelectedClipsAutocaching);
if (clip->connected_viewer()) {
QAction *reveal_in_footage_viewer = menu.addAction(tr("Reveal in Footage Viewer"));
reveal_in_footage_viewer->setData(reinterpret_cast<quintptr>(clip->connected_viewer()));
reveal_in_footage_viewer->setProperty("range", QVariant::fromValue(clip->media_range()));
connect(reveal_in_footage_viewer, &QAction::triggered, this, &TimelineWidget::RevealInFootageViewer);
QAction *reveal_in_project = menu.addAction(tr("Reveal in Project"));
reveal_in_project->setData(reinterpret_cast<quintptr>(clip->connected_viewer()));
connect(reveal_in_project, &QAction::triggered, this, &TimelineWidget::RevealInProject);
@@ -1221,6 +1242,16 @@ void TimelineWidget::SignalBlockSelectionChange()
signal_block_change_timer_->start();
}
void TimelineWidget::RevealInFootageViewer()
{
QAction *a = static_cast<QAction*>(sender());
ViewerOutput *item_to_reveal = reinterpret_cast<ViewerOutput*>(a->data().value<quintptr>());
TimeRange r = a->property("range").value<TimeRange>();
emit RevealViewerInFootageViewer(item_to_reveal, r);
}
void TimelineWidget::RevealInProject()
{
QAction *a = static_cast<QAction*>(sender());
@@ -79,6 +79,8 @@ public:
void ToggleLinksOnSelected();
void AddDefaultTransitionsToSelected();
virtual bool CopySelected(bool cut) override;
virtual bool Paste() override;
@@ -277,6 +279,7 @@ signals:
void RequestCaptureStart(const TimeRange &time, const Track::Reference &track);
void RevealViewerInFootageViewer(ViewerOutput *r, const TimeRange &range);
void RevealViewerInProject(ViewerOutput *r);
protected:
@@ -427,6 +430,7 @@ private slots:
void SignalBlockSelectionChange();
void RevealInFootageViewer();
void RevealInProject();
void RenameSelectedBlocks();
+1 -1
View File
@@ -231,7 +231,7 @@ void ImportTool::FootageToGhosts(rational ghost_start, const DraggedFootageData
rational footage_duration;
rational ghost_in;
TimelineWorkArea* wk = footage->GetTimelinePoints()->workarea();
TimelineWorkArea* wk = footage->GetWorkArea();
if (wk->enabled()) {
footage_duration = wk->length();
ghost_in = wk->in();
+18 -1
View File
@@ -689,6 +689,8 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
InsertGapsAtGhostDestination(command);
}
QMap<Node*, Node*> relinks;
// Now we can re-add each clip
foreach (const GhostBlockPair& p, blocks_moving) {
Block* block = p.block;
@@ -696,7 +698,10 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
if (duplicate_clips) {
// Duplicate rather than move
// Place the copy instead of the original block
block = static_cast<Block*>(Node::CopyNodeInGraph(block, command));
Block *new_block = static_cast<Block*>(Node::CopyNodeInGraph(block, command));
relinks.insert(block, new_block);
block = new_block;
if (ClipBlock *new_clip = dynamic_cast<ClipBlock*>(block)) {
new_clip->AddCachePassthroughFrom(static_cast<ClipBlock*>(p.block));
}
@@ -709,6 +714,18 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
p.ghost->GetAdjustedIn()));
}
if (!relinks.empty()) {
for (auto it=relinks.cbegin(); it!=relinks.cend(); it++) {
for (auto jt=it.key()->links().cbegin(); jt!=it.key()->links().cend(); jt++) {
Node *link = *jt;
Node *copy_link = relinks.value(link);
if (copy_link) {
command->add_child(new NodeLinkCommand(it.value(), copy_link, true));
}
}
}
}
// Adjust selections
TimelineWidgetSelections new_sel = parent()->GetSelections();
new_sel.ShiftTime(blocks_moving.first().ghost->GetInAdjustment());
@@ -22,9 +22,11 @@
#include "node/block/clip/clip.h"
#include "node/block/transition/transition.h"
#include "node/factory.h"
#include "node/math/math/math.h"
#include "node/math/merge/merge.h"
#include "timelineundocommon.h"
#include "widget/timelinewidget/undo/timelineundotrack.h"
namespace olive {
@@ -287,8 +289,8 @@ void TrackListInsertGaps::prepare()
QVector<Block*> blocks_to_append_gap_to;
QVector<Track*> tracks_to_append_gap_to;
foreach (Track* track, working_tracks_) {
foreach (Block* b, track->Blocks()) {
for (Track* track : qAsConst(working_tracks_)) {
for (Block* b : track->Blocks()) {
if (dynamic_cast<GapBlock*>(b) && b->in() <= point_ && b->out() >= point_) {
// Found a gap at the location
gaps_to_extend_.append(b);
@@ -542,4 +544,121 @@ void TimelineRemoveTrackCommand::undo()
remove_command_->undo_now();
}
void TimelineAddDefaultTransitionCommand::prepare()
{
for (auto it=clips_.cbegin(); it!=clips_.cend(); it++) {
ClipBlock *c = *it;
// Handle in transition
if (clips_.contains(static_cast<ClipBlock*>(c->previous()))) {
// Do nothing, assume this will be handled by a dual transition from that clip
} else if (dynamic_cast<GapBlock*>(c->previous()) || !c->previous()) {
// Create in transition
AddTransition(c, kIn);
}
// Handle out transition
if (clips_.contains(static_cast<ClipBlock*>(c->next()))) {
AddTransition(c, kOutDual);
} else if (dynamic_cast<GapBlock*>(c->next()) || !c->next()) {
// Create out transition
AddTransition(c, kOut);
}
}
}
void TimelineAddDefaultTransitionCommand::AddTransition(ClipBlock *c, CreateTransitionMode mode)
{
if (Track *t = c->track()) {
Node *p = nullptr;
if (t->type() == Track::kVideo) {
p = NodeFactory::CreateFromID(OLIVE_CONFIG("DefaultVideoTransition").toString());
} else if (t->type() == Track::kAudio) {
p = NodeFactory::CreateFromID(OLIVE_CONFIG("DefaultAudioTransition").toString());
}
rational transition_length = OLIVE_CONFIG("DefaultTransitionLength").value<rational>();
// Resize original clip
switch (mode) {
case kIn:
ValidateTransitionLength(c, transition_length);
if (transition_length > 0) {
AdjustClipLength(c, transition_length, false);
}
break;
case kOut:
ValidateTransitionLength(c, transition_length);
if (transition_length > 0) {
AdjustClipLength(c, transition_length, true);
}
break;
case kOutDual:
{
rational half_length = transition_length / 2;
ValidateTransitionLength(static_cast<ClipBlock*>(c->next()), half_length);
ValidateTransitionLength(c, half_length);
transition_length = half_length * 2;
if (transition_length > 0) {
AdjustClipLength(static_cast<ClipBlock*>(c->next()), half_length, false);
AdjustClipLength(c, half_length, true);
}
break;
}
}
if (transition_length > 0) {
if (TransitionBlock *transition = dynamic_cast<TransitionBlock*>(p)) {
transition->set_length_and_media_out(transition_length);
// Add transition
commands_.append(new NodeAddCommand(c->parent(), transition));
// Insert block
Block *insert_after = (mode == kIn) ? c->previous() : c;
commands_.append(new TrackInsertBlockAfterCommand(c->track(), transition, insert_after));
// Connect
switch (mode) {
case kIn:
commands_.append(new NodeEdgeAddCommand(c, NodeInput(transition, TransitionBlock::kInBlockInput)));
break;
case kOutDual:
commands_.append(new NodeEdgeAddCommand(c->next(), NodeInput(transition, TransitionBlock::kInBlockInput)));
/* fall through */
case kOut:
commands_.append(new NodeEdgeAddCommand(c, NodeInput(transition, TransitionBlock::kOutBlockInput)));
break;
}
}
}
}
}
void TimelineAddDefaultTransitionCommand::AdjustClipLength(ClipBlock *c, const rational &transition_length, bool out)
{
rational cur_len = lengths_.value(c, c->length());
rational new_len = cur_len - transition_length;
if (out) {
commands_.append(new BlockResizeCommand(c, new_len));
} else {
commands_.append(new BlockResizeWithMediaInCommand(c, new_len));
}
lengths_.insert(c, new_len);
}
void TimelineAddDefaultTransitionCommand::ValidateTransitionLength(ClipBlock *c, rational &transition_length)
{
rational cur_len = lengths_.value(c, c->length());
rational half_cur_len = cur_len/2;
if (transition_length >= half_cur_len) {
transition_length = half_cur_len - timebase_;
}
}
}
@@ -358,6 +358,61 @@ private:
};
class TimelineAddDefaultTransitionCommand : public UndoCommand
{
public:
TimelineAddDefaultTransitionCommand(const QVector<ClipBlock*> &clips, const rational &timebase) :
clips_(clips),
timebase_(timebase)
{}
virtual ~TimelineAddDefaultTransitionCommand() override
{
qDeleteAll(commands_);
}
virtual Project* GetRelevantProject() const override
{
return clips_.empty() ? nullptr : clips_.first()->project();
}
protected:
virtual void prepare() override;
virtual void redo() override
{
for (auto it=commands_.cbegin(); it!=commands_.cend(); it++) {
(*it)->redo_now();
}
}
virtual void undo() override
{
for (auto it=commands_.crbegin(); it!=commands_.crend(); it++) {
(*it)->undo_now();
}
}
private:
enum CreateTransitionMode {
kIn,
kOut,
kOutDual
};
void AddTransition(ClipBlock *c, CreateTransitionMode mode);
void AdjustClipLength(ClipBlock *c, const rational &transition_length, bool out);
void ValidateTransitionLength(ClipBlock *c, rational &transition_length);
QVector<ClipBlock*> clips_;
rational timebase_;
QVector<UndoCommand*> commands_;
QHash<ClipBlock*, rational> lengths_;
};
}
#endif // TIMELINEUNDOGENERAL_H
@@ -22,16 +22,15 @@
#define TIMELINEUNDOWORKAREA_H
#include "node/project/project.h"
#include "timeline/timelinepoints.h"
namespace olive {
class WorkareaSetEnabledCommand : public UndoCommand {
public:
WorkareaSetEnabledCommand(Project *project, TimelinePoints* points, bool enabled) :
WorkareaSetEnabledCommand(Project *project, TimelineWorkArea* points, bool enabled) :
project_(project),
points_(points),
old_enabled_(points_->workarea()->enabled()),
old_enabled_(points_->enabled()),
new_enabled_(enabled)
{
}
@@ -44,18 +43,18 @@ public:
protected:
virtual void redo() override
{
points_->workarea()->set_enabled(new_enabled_);
points_->set_enabled(new_enabled_);
}
virtual void undo() override
{
points_->workarea()->set_enabled(old_enabled_);
points_->set_enabled(old_enabled_);
}
private:
Project* project_;
TimelinePoints* points_;
TimelineWorkArea* points_;
bool old_enabled_;
@@ -585,7 +585,7 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
}
}
TimelineMarkerList *marker_list = clip->connected_viewer()->GetTimelinePoints()->markers();
TimelineMarkerList *marker_list = clip->connected_viewer()->GetMarkers();
if (!marker_list->empty()) {
clip_marker_rects_.clear();
@@ -752,12 +752,14 @@ void TimelineView::ConnectTrackList(TrackList *list)
{
if (connected_track_list_) {
disconnect(connected_track_list_, &TrackList::TrackListChanged, this, &TimelineView::TrackListChanged);
disconnect(connected_track_list_, &TrackList::TrackHeightChanged, this, &TimelineView::TrackListChanged);
}
connected_track_list_ = list;
if (connected_track_list_) {
connect(connected_track_list_, &TrackList::TrackListChanged, this, &TimelineView::TrackListChanged);
connect(connected_track_list_, &TrackList::TrackHeightChanged, this, &TimelineView::TrackListChanged);
}
}
+129 -90
View File
@@ -41,7 +41,8 @@ namespace olive {
SeekableWidget::SeekableWidget(QWidget* parent) :
super(parent),
timeline_points_(nullptr),
markers_(nullptr),
workarea_(nullptr),
dragging_(false),
ignore_next_focus_out_(false),
selection_manager_(this),
@@ -63,26 +64,41 @@ SeekableWidget::SeekableWidget(QWidget* parent) :
selection_manager_.SetSnapMask(TimeBasedWidget::kSnapAll);
}
void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points)
void SeekableWidget::SetMarkers(TimelineMarkerList *markers)
{
if (timeline_points_) {
if (markers_) {
selection_manager_.ClearSelection();
disconnect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(timeline_points_->markers(), &TimelineMarkerList::MarkerModified, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(markers_, &TimelineMarkerList::MarkerAdded, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(markers_, &TimelineMarkerList::MarkerRemoved, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(markers_, &TimelineMarkerList::MarkerModified, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
}
timeline_points_ = points;
markers_ = markers;
if (timeline_points_) {
connect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerAdded, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerRemoved, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(timeline_points_->markers(), &TimelineMarkerList::MarkerModified, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
if (markers_) {
connect(markers_, &TimelineMarkerList::MarkerAdded, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(markers_, &TimelineMarkerList::MarkerRemoved, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(markers_, &TimelineMarkerList::MarkerModified, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
}
viewport()->update();
}
void SeekableWidget::SetWorkArea(TimelineWorkArea *workarea)
{
if (workarea_) {
selection_manager_.ClearSelection();
disconnect(workarea_, &TimelineWorkArea::RangeChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
disconnect(workarea_, &TimelineWorkArea::EnabledChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
}
workarea_ = workarea;
if (workarea_) {
connect(workarea_, &TimelineWorkArea::RangeChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
connect(workarea_, &TimelineWorkArea::EnabledChanged, viewport(), static_cast<void (QWidget::*)()>(&QWidget::update));
}
viewport()->update();
@@ -139,11 +155,11 @@ bool SeekableWidget::PasteMarkers()
m->set_time(m->time().in() - min);
if (TimelineMarker *existing = timeline_points_->markers()->GetMarkerAtTime(m->time().in())) {
if (TimelineMarker *existing = markers_->GetMarkerAtTime(m->time().in())) {
command->add_child(new MarkerRemoveCommand(existing));
}
command->add_child(new MarkerAddCommand(timeline_points_->markers(), m));
command->add_child(new MarkerAddCommand(markers_, m));
}
Core::instance()->undo_stack()->push(command);
@@ -187,7 +203,7 @@ void SeekableWidget::mouseMoveEvent(QMouseEvent *event)
} else {
SeekToScenePoint(scene.x());
}
} else if (timeline_points_) {
} else {
// Look for resize points
if (FindResizeHandle(event)) {
setCursor(Qt::SizeHorCursor);
@@ -238,6 +254,59 @@ void SeekableWidget::focusOutEvent(QFocusEvent *event)
}
}
void SeekableWidget::DrawMarkers(QPainter *p, int marker_bottom)
{
selection_manager_.ClearDrawnObjects();
// Draw markers
if (markers_ && !markers_->empty() && marker_bottom > 0) {
int lim_left = GetLeftLimit();
int lim_right = GetRightLimit();
for (auto it=markers_->cbegin(); it!=markers_->cend(); it++) {
TimelineMarker* marker = *it;
int marker_right = TimeToScene(marker->time().out());
if (marker_right < lim_left) {
continue;
}
int marker_left = TimeToScene(marker->time().in());
if (marker_left >= lim_right) {
break;
}
QRect marker_rect = marker->Draw(p, QPoint(marker_left, marker_bottom), GetScale(), selection_manager_.IsSelected(marker));
marker_top_ = marker_rect.top();
selection_manager_.DeclareDrawnObject(marker, marker_rect);
}
}
marker_bottom_ = marker_bottom;
}
void SeekableWidget::DrawWorkArea(QPainter *p)
{
// Draw in/out workarea
if (workarea_ && workarea_->enabled()) {
int lim_left = GetLeftLimit();
int lim_right = GetRightLimit();
int workarea_left = qMax(qreal(lim_left), TimeToScene(workarea_->in()));
int workarea_right;
if (workarea_->out() == TimelineWorkArea::kResetOut) {
workarea_right = lim_right;
} else {
workarea_right = qMin(qreal(lim_right), TimeToScene(workarea_->out()));
}
QColor translucent_highlight = palette().highlight().color();
translucent_highlight.setAlpha(96);
p->fillRect(workarea_left, 0, workarea_right - workarea_left, height(), translucent_highlight);
}
}
void SeekableWidget::DeselectAllMarkers()
{
selection_manager_.ClearSelection();
@@ -309,61 +378,15 @@ void SeekableWidget::SelectionManagerDeselectEvent(void *obj)
viewport()->update();
}
void SeekableWidget::DrawTimelinePoints(QPainter* p, int marker_bottom)
{
if (!GetTimelinePoints()) {
return;
}
int lim_left = GetScroll();
int lim_right = lim_left + width();
selection_manager_.ClearDrawnObjects();
// Draw in/out workarea
if (GetTimelinePoints()->workarea()->enabled()) {
int workarea_left = qMax(qreal(lim_left), TimeToScene(GetTimelinePoints()->workarea()->in()));
int workarea_right;
if (GetTimelinePoints()->workarea()->out() == TimelineWorkArea::kResetOut) {
workarea_right = lim_right;
} else {
workarea_right = qMin(qreal(lim_right), TimeToScene(GetTimelinePoints()->workarea()->out()));
}
p->fillRect(workarea_left, 0, workarea_right - workarea_left, height(), palette().highlight());
}
// Draw markers
if (marker_bottom > 0 && !GetTimelinePoints()->markers()->empty()) {
for (auto it=GetTimelinePoints()->markers()->cbegin(); it!=GetTimelinePoints()->markers()->cend(); it++) {
TimelineMarker* marker = *it;
int marker_right = TimeToScene(marker->time().out());
if (marker_right < lim_left) {
continue;
}
int marker_left = TimeToScene(marker->time().in());
if (marker_left >= lim_right) {
break;
}
QRect marker_rect = marker->Draw(p, QPoint(marker_left, marker_bottom), GetScale(), selection_manager_.IsSelected(marker));
marker_top_ = marker_rect.top();
selection_manager_.DeclareDrawnObject(marker, marker_rect);
}
}
marker_bottom_ = marker_bottom;
}
void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y)
{
int half_width = playhead_width_ / 2;
if (x + half_width < 0 || x - half_width > width()) {
return;
{
int test = x - this->GetScroll();
if (test + half_width < 0 || test - half_width > width()) {
return;
}
}
p->setRenderHint(QPainter::Antialiasing);
@@ -384,6 +407,16 @@ void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y)
p->setRenderHint(QPainter::Antialiasing, false);
}
int SeekableWidget::GetLeftLimit() const
{
return GetScroll();
}
int SeekableWidget::GetRightLimit() const
{
return GetLeftLimit() + width();
}
bool SeekableWidget::ShowContextMenu(const QPoint &p)
{
if (selection_manager_.GetObjectAtPoint(p) && !selection_manager_.GetSelectedObjects().empty()) {
@@ -422,32 +455,38 @@ bool SeekableWidget::FindResizeHandle(QMouseEvent *event)
rational max = SceneToTimeNoGrid(scene.x() + border);
// Test for workarea
if (timeline_points_->workarea()->in() >= min && timeline_points_->workarea()->in() < max) {
resize_mode_ = kResizeIn;
} else if (timeline_points_->workarea()->out() >= min && timeline_points_->workarea()->out() < max) {
resize_mode_ = kResizeOut;
if (workarea_) {
if (workarea_->in() >= min && workarea_->in() < max) {
resize_mode_ = kResizeIn;
} else if (workarea_->out() >= min && workarea_->out() < max) {
resize_mode_ = kResizeOut;
}
}
if (resize_mode_ != kResizeNone) {
resize_item_ = timeline_points_->workarea();
resize_item_range_ = timeline_points_->workarea()->range();
resize_snap_mask_ = TimeBasedWidget::kSnapAll & ~TimeBasedWidget::kSnapToWorkarea;
if (workarea_) {
resize_item_ = workarea_;
resize_item_range_ = workarea_->range();
resize_snap_mask_ = TimeBasedWidget::kSnapAll & ~TimeBasedWidget::kSnapToWorkarea;
}
} else if (event->pos().y() >= marker_top_ && event->pos().y() < marker_bottom_) {
// Check for markers
for (auto it=timeline_points_->markers()->cbegin(); it!=timeline_points_->markers()->cend(); it++) {
TimelineMarker *m = *it;
if (m->time().in() != m->time().out()) {
if (m->time().in() >= min && m->time().in() < max) {
resize_mode_ = kResizeIn;
} else if (m->time().out() >= min && m->time().out() < max) {
resize_mode_ = kResizeOut;
}
if (markers_) {
// Check for markers
for (auto it=markers_->cbegin(); it!=markers_->cend(); it++) {
TimelineMarker *m = *it;
if (m->time().in() != m->time().out()) {
if (m->time().in() >= min && m->time().in() < max) {
resize_mode_ = kResizeIn;
} else if (m->time().out() >= min && m->time().out() < max) {
resize_mode_ = kResizeOut;
}
if (resize_mode_ != kResizeNone) {
resize_item_ = m;
resize_item_range_ = m->time();
resize_snap_mask_ = TimeBasedWidget::kSnapAll;
break;
if (resize_mode_ != kResizeNone) {
resize_item_ = m;
resize_item_range_ = m->time();
resize_snap_mask_ = TimeBasedWidget::kSnapAll;
break;
}
}
}
}
+12 -5
View File
@@ -25,7 +25,6 @@
#include <QScrollBar>
#include "common/rational.h"
#include "timeline/timelinepoints.h"
#include "widget/menu/menu.h"
#include "widget/timebased/timebasedviewselectionmanager.h"
@@ -42,8 +41,11 @@ public:
return horizontalScrollBar()->value();
}
TimelinePoints* GetTimelinePoints() const { return timeline_points_; }
void ConnectTimelinePoints(TimelinePoints* points);
TimelineMarkerList *GetMarkers() const { return markers_; }
TimelineWorkArea *GetWorkArea() const { return workarea_; }
void SetMarkers(TimelineMarkerList *markers);
void SetWorkArea(TimelineWorkArea *workarea);
bool IsDraggingPlayhead() const
{
@@ -84,7 +86,8 @@ protected:
virtual void focusOutEvent(QFocusEvent *event) override;
void DrawTimelinePoints(QPainter *p, int marker_bottom = 0);
void DrawMarkers(QPainter *p, int marker_bottom = 0);
void DrawWorkArea(QPainter *p);
void DrawPlayhead(QPainter* p, int x, int y);
@@ -96,6 +99,9 @@ protected:
return playhead_width_;
}
int GetLeftLimit() const;
int GetRightLimit() const;
protected slots:
virtual bool ShowContextMenu(const QPoint &p);
@@ -112,7 +118,8 @@ private:
void CommitResizeHandle();
TimelinePoints* timeline_points_;
TimelineMarkerList* markers_;
TimelineWorkArea* workarea_;
int text_height_;
+2 -3
View File
@@ -102,9 +102,8 @@ void TimeRuler::drawForeground(QPainter *p, const QRectF &rect)
// Draw timeline points if connected
int marker_height = TimelineMarker::GetMarkerHeight(p->fontMetrics());
if (GetTimelinePoints()) {
DrawTimelinePoints(p, marker_height);
}
DrawMarkers(p, marker_height);
DrawWorkArea(p);
double width_of_frame = timebase_dbl() * GetScale();
double width_of_second = 0;
+2 -1
View File
@@ -86,7 +86,8 @@ void AudioWaveformView::drawForeground(QPainter *p, const QRectF &rect)
}
// Draw in/out points
DrawTimelinePoints(p);
DrawWorkArea(p);
DrawMarkers(p);
// Draw waveform
p->setPen(QColor(64, 255, 160)); // FIXME: Hardcoded color
+16
View File
@@ -38,6 +38,22 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
controls_->SetAudioVideoDragButtonsVisible(true);
connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag);
connect(controls_, &PlaybackControls::AudioPressed, this, &FootageViewerWidget::StartAudioDrag);
override_workarea_ = new TimelineWorkArea(this);
}
void FootageViewerWidget::OverrideWorkArea(const TimeRange &r)
{
override_workarea_->set_enabled(true);
override_workarea_->set_range(r);
this->ConnectWorkArea(override_workarea_);
}
void FootageViewerWidget::ResetWorkArea()
{
if (GetConnectedWorkArea() == override_workarea_) {
this->ConnectWorkArea(GetConnectedNode() ? GetConnectedNode()->GetWorkArea() : nullptr);
}
}
void FootageViewerWidget::ConnectNodeEvent(ViewerOutput *n)
+5
View File
@@ -32,6 +32,9 @@ class FootageViewerWidget : public ViewerWidget
public:
FootageViewerWidget(QWidget* parent = nullptr);
void OverrideWorkArea(const TimeRange &r);
void ResetWorkArea();
protected:
virtual void ConnectNodeEvent(ViewerOutput *) override;
@@ -42,6 +45,8 @@ private:
QHash<ViewerOutput*, rational> cached_timestamps_;
TimelineWorkArea *override_workarea_;
private slots:
void StartFootageDrag();
+102 -62
View File
@@ -45,6 +45,7 @@
#include "viewerpreventsleep.h"
#include "widget/menu/menu.h"
#include "window/mainwindow/mainwindow.h"
#include "widget/nodeparamview/nodeparamviewundo.h"
#include "widget/timelinewidget/tool/add.h"
#include "widget/timeruler/timeruler.h"
@@ -72,19 +73,17 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
record_armed_(false),
recording_(false),
first_requeue_watcher_(nullptr),
enable_audio_scrubbing_(true)
enable_audio_scrubbing_(true),
waveform_mode_(kWFAutomatic)
{
// Set up main layout
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
// Set up stacked widget to allow switching away from the viewer widget
stack_ = new QStackedWidget();
layout->addWidget(stack_);
// Create main OpenGL-based view and sizer
sizer_ = new ViewerSizer();
stack_->addWidget(sizer_);
sizer_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(sizer_);
display_widget_ = new ViewerDisplayWidget();
display_widget_->setAcceptDrops(true);
@@ -114,7 +113,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
waveform_view_ = new AudioWaveformView();
ConnectTimelineView(waveform_view_, true);
PassWheelEventsToScrollBar(waveform_view_);
stack_->addWidget(waveform_view_);
layout->addWidget(waveform_view_);
// Create time ruler
layout->addWidget(ruler());
@@ -210,9 +209,10 @@ void ViewerWidget::ConnectNodeEvent(ViewerOutput *n)
connect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
connect(n, &ViewerOutput::InterlacingChanged, this, &ViewerWidget::InterlacingChangedSlot);
connect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateRendererVideoParameters);
connect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateTextureFromNode, Qt::QueuedConnection);
connect(n, &ViewerOutput::AudioParamsChanged, this, &ViewerWidget::UpdateRendererAudioParameters);
connect(n->video_frame_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedVideoRange);
connect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateStack);
connect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateWaveformViewFromMode);
VideoParams vp = n->GetVideoParams();
@@ -233,10 +233,9 @@ void ViewerWidget::ConnectNodeEvent(ViewerOutput *n)
dw->ConnectColorManager(color_manager);
}
UpdateStack();
UpdateWaveformViewFromMode();
waveform_view_->SetViewer(GetConnectedNode());
waveform_view_->ConnectTimelinePoints(GetConnectedNode()->GetTimelinePoints());
UpdateRendererVideoParameters();
UpdateRendererAudioParameters();
@@ -254,9 +253,10 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
disconnect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot);
disconnect(n, &ViewerOutput::InterlacingChanged, this, &ViewerWidget::InterlacingChangedSlot);
disconnect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateRendererVideoParameters);
disconnect(n, &ViewerOutput::VideoParamsChanged, this, &ViewerWidget::UpdateTextureFromNode);
disconnect(n, &ViewerOutput::AudioParamsChanged, this, &ViewerWidget::UpdateRendererAudioParameters);
disconnect(n->video_frame_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedVideoRange);
disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateStack);
disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateWaveformViewFromMode);
CloseAudioProcessor();
@@ -272,10 +272,9 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
}
waveform_view_->SetViewer(nullptr);
waveform_view_->ConnectTimelinePoints(nullptr);
// Queue an UpdateStack so that when it runs, the viewer node will be fully disconnected
QMetaObject::invokeMethod(this, &ViewerWidget::UpdateStack, Qt::QueuedConnection);
QMetaObject::invokeMethod(this, &ViewerWidget::UpdateWaveformViewFromMode, Qt::QueuedConnection);
SetGizmos(nullptr);
}
@@ -286,6 +285,16 @@ void ViewerWidget::ConnectedNodeChangeEvent(ViewerOutput *n)
display_widget_->SetSubtitleTracks(dynamic_cast<Sequence*>(n));
}
void ViewerWidget::ConnectedWorkAreaChangeEvent(TimelineWorkArea *workarea)
{
waveform_view_->SetWorkArea(workarea);
}
void ViewerWidget::ConnectedMarkersChangeEvent(TimelineMarkerList *markers)
{
waveform_view_->SetMarkers(markers);
}
void ViewerWidget::ScaleChangedEvent(const double &s)
{
super::ScaleChangedEvent(s);
@@ -381,8 +390,8 @@ void ViewerWidget::CacheEntireSequence()
void ViewerWidget::CacheSequenceInOut()
{
if (GetConnectedNode() && GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
auto_cacher_->ForceCacheRange(GetConnectedNode()->GetTimelinePoints()->workarea()->range());
if (GetConnectedNode() && GetConnectedNode()->GetWorkArea()->enabled()) {
auto_cacher_->ForceCacheRange(GetConnectedNode()->GetWorkArea()->range());
} else {
QMessageBox::warning(this,
tr("Error"),
@@ -528,11 +537,35 @@ void ViewerWidget::CreateAddableAt(const QRectF &f)
}
}
void ViewerWidget::HandleFirstRequeueDestroy()
{
// Extra protection to ensure we don't reference a destroyed object
if (first_requeue_watcher_ == sender()) {
first_requeue_watcher_ = nullptr;
}
}
void ViewerWidget::CloseAudioProcessor()
{
audio_processor_.Close();
}
void ViewerWidget::SetWaveformMode(WaveformMode wf)
{
waveform_mode_ = wf;
UpdateWaveformViewFromMode();
}
void ViewerWidget::UpdateWaveformViewFromMode()
{
bool prefer_waveform = ShouldForceWaveform();
sizer_->setVisible(waveform_mode_ == kWFViewerAndWaveform || waveform_mode_ == kWFViewerOnly || (waveform_mode_ == kWFAutomatic && !prefer_waveform));
waveform_view_->setVisible(waveform_mode_ == kWFViewerAndWaveform || waveform_mode_ == kWFWaveformOnly || (waveform_mode_ == kWFAutomatic && prefer_waveform));
waveform_view_->setSizePolicy(QSizePolicy::Expanding, waveform_mode_ == kWFViewerAndWaveform ? QSizePolicy::Maximum : QSizePolicy::Expanding);
}
void ViewerWidget::QueueNextAudioBuffer()
{
rational queue_end = audio_playback_queue_time_ + (kAudioPlaybackInterval * playback_speed_);
@@ -551,7 +584,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), RenderTicketPriority::kHigh));
watcher->SetTicket(auto_cacher_->GetRangeOfAudio(TimeRange(audio_playback_queue_time_, queue_end)));
audio_playback_queue_time_ = queue_end;
}
@@ -674,6 +707,7 @@ void ViewerWidget::ForceRequeueFromCurrentTime()
RenderTicketWatcher *watcher = RequestNextFrameForQueue();
if (!first_requeue_watcher_) {
first_requeue_watcher_ = watcher;
connect(first_requeue_watcher_, &RenderTicketWatcher::destroyed, this, &ViewerWidget::HandleFirstRequeueDestroy);
}
}
}
@@ -705,7 +739,7 @@ void ViewerWidget::UpdateTextureFromNode()
// Clear queue because we want this frame more than any others
auto_cacher_->ClearSingleFrameRenders();
watcher->SetTicket(GetFrame(time, RenderTicketPriority::kNormal));
watcher->SetTicket(GetFrame(time));
} else {
// There is definitely no frame here, we can immediately flip to showing nothing
nonqueue_watchers_.clear();
@@ -736,6 +770,8 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
viewer->auto_cacher_->SetRendersPaused(true);
}
RenderManager::instance()->SetAggressiveGarbageCollection(true);
// Disarm recording if armed
if (record_armed_) {
DisarmRecording();
@@ -833,6 +869,8 @@ void ViewerWidget::PauseInternal()
}
UpdateTextureFromNode();
RenderManager::instance()->SetAggressiveGarbageCollection(false);
}
prequeuing_video_ = false;
@@ -854,7 +892,7 @@ void ViewerWidget::PushScrubbedAudio()
RenderTicketWatcher *watcher = new RenderTicketWatcher();
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::ReceivedAudioBufferForScrubbing);
watcher->SetTicket(auto_cacher_->GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval), RenderTicketPriority::kHigh));
watcher->SetTicket(auto_cacher_->GetRangeOfAudio(TimeRange(GetTime(), GetTime() + interval)));
}
}
}
@@ -904,7 +942,7 @@ void ViewerWidget::SetDisplayImage(QVariant frame)
}
}
RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(RenderTicketPriority priority, bool increment)
RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(bool increment)
{
RenderTicketWatcher *watcher = nullptr;
@@ -920,19 +958,19 @@ RenderTicketWatcher *ViewerWidget::RequestNextFrameForQueue(RenderTicketPriority
watcher->setProperty("time", QVariant::fromValue(next_time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
queue_watchers_.append(watcher);
watcher->SetTicket(GetFrame(next_time, priority));
watcher->SetTicket(GetFrame(next_time));
}
return watcher;
}
RenderTicketPtr ViewerWidget::GetFrame(const rational &t, RenderTicketPriority priority)
RenderTicketPtr ViewerWidget::GetFrame(const rational &t)
{
QString cache_fn = GetConnectedNode()->video_frame_cache()->GetValidCacheFilename(t);
if (!QFileInfo::exists(cache_fn)) {
// Frame hasn't been cached, start render job
return auto_cacher_->GetSingleFrame(t, priority);
return auto_cacher_->GetSingleFrame(t);
} else {
// Frame has been cached, grab the frame
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
@@ -1000,33 +1038,22 @@ int ViewerWidget::DeterminePlaybackQueueSize()
return qMin(max_frames, remaining_frames);
}
void ViewerWidget::UpdateStack()
{
rational new_tb;
if (ShouldForceWaveform()) {
// If we have a node AND video is disconnected AND audio is connected, show waveform view
stack_->setCurrentWidget(waveform_view_);
//new_tb = GetConnectedNode()->audio_params().time_base();
} else {
// Otherwise show regular display
stack_->setCurrentWidget(sizer_);
/*if (GetConnectedNode()) {
new_tb = GetConnectedNode()->video_params().time_base();
}*/
}
/*if (new_tb != timebase()) {
SetTimebase(new_tb);
}*/
}
void ViewerWidget::ContextMenuSetFullScreen(QAction *action)
{
SetFullScreen(QGuiApplication::screens().at(action->data().toInt()));
}
void ViewerWidget::ContextMenuSetPlaybackRes(QAction *action)
{
int div = action->data().toInt();
auto vp = GetConnectedNode()->GetVideoParams();
vp.set_divider(div);
auto c = new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(GetConnectedNode(), ViewerOutput::kVideoParamsInput, 0)), QVariant::fromValue(vp));
Core::instance()->undo_stack()->push(c);
}
void ViewerWidget::ContextMenuDisableSafeMargins()
{
context_menu_widget_->SetSafeMargins(ViewerSafeMarginInfo(false));
@@ -1102,7 +1129,9 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
prequeuing_video_ = false;
FinishPlayPreprocess();
} else {
RequestNextFrameForQueue();
// This call was mostly necessary to keep the threads busy between prequeue and playback.
// If we only have a single render thread, it's no longer necessary.
//RequestNextFrameForQueue();
}
}
}
@@ -1182,6 +1211,18 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
connect(full_screen_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuSetFullScreen);
}
{
// Playback Resolution Menu
Menu *playback_res_menu = new Menu(tr("Playback Resolution"), &menu);
menu.addMenu(playback_res_menu);
for (int d : VideoParams::kSupportedDividers) {
playback_res_menu->AddActionWithData(VideoParams::GetNameForDivider(d), d, GetConnectedNode()->GetVideoParams().divider());
}
connect(playback_res_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuSetPlaybackRes);
}
{
// Deinterlace Option
if (GetConnectedNode()->GetVideoParams().interlacing() != VideoParams::kInterlaceNone) {
@@ -1245,11 +1286,14 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
}
{
QAction* show_waveform_action = menu.addAction(tr("Show Audio Waveform"));
show_waveform_action->setCheckable(true);
show_waveform_action->setChecked(stack_->currentWidget() == waveform_view_);
show_waveform_action->setEnabled(!ShouldForceWaveform());
connect(show_waveform_action, &QAction::triggered, this, &ViewerWidget::ManualSwitchToWaveform);
auto waveform_menu = new Menu(tr("Audio Waveform"), &menu);
menu.addMenu(waveform_menu);
waveform_menu->AddActionWithData(tr("Automatically Show/Hide"), kWFAutomatic, waveform_mode_);
waveform_menu->AddActionWithData(tr("Show Waveform Only"), kWFWaveformOnly, waveform_mode_);
waveform_menu->AddActionWithData(tr("Show Both Viewer And Waveform"), kWFViewerAndWaveform, waveform_mode_);
connect(waveform_menu, &Menu::triggered, this, &ViewerWidget::UpdateWaveformModeFromMenu);
}
{
@@ -1273,9 +1317,9 @@ void ViewerWidget::Play(bool in_to_out_only)
{
if (in_to_out_only) {
if (GetConnectedNode()
&& GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
&& GetConnectedNode()->GetWorkArea()->enabled()) {
// Jump to in point
SetTimeAndSignal(GetConnectedNode()->GetTimelinePoints()->workarea()->in());
SetTimeAndSignal(GetConnectedNode()->GetWorkArea()->in());
} else {
in_to_out_only = false;
}
@@ -1403,11 +1447,11 @@ void ViewerWidget::PlaybackTimerUpdate()
min_time = recording_range_.in();
max_time = recording_range_.out();
} else if (play_in_to_out_only_ && GetConnectedNode()->GetTimelinePoints()->workarea()->enabled()) {
} else if (play_in_to_out_only_ && GetConnectedNode()->GetWorkArea()->enabled()) {
// If "play in to out" is enabled or we're looping AND we have a workarea, only play the workarea
min_time = GetConnectedNode()->GetTimelinePoints()->workarea()->in();
max_time = GetConnectedNode()->GetTimelinePoints()->workarea()->out();
min_time = GetConnectedNode()->GetWorkArea()->in();
max_time = GetConnectedNode()->GetWorkArea()->out();
} else {
@@ -1483,7 +1527,7 @@ void ViewerWidget::PlaybackTimerUpdate()
}
if (IsPlaying()) {
while (queue_watchers_.size() < DeterminePlaybackQueueSize()) {
while ((int(display_widget_->queue()->size()) + queue_watchers_.size()) < DeterminePlaybackQueueSize()) {
if (!RequestNextFrameForQueue()) {
// Prevent infinite loop
break;
@@ -1565,13 +1609,9 @@ void ViewerWidget::ViewerInvalidatedVideoRange(const TimeRange &range)
}
}
void ViewerWidget::ManualSwitchToWaveform(bool e)
void ViewerWidget::UpdateWaveformModeFromMenu(QAction *a)
{
if (e) {
stack_->setCurrentWidget(waveform_view_);
} else {
stack_->setCurrentWidget(sizer_);
}
SetWaveformMode(static_cast<WaveformMode>(a->data().toInt()));
}
void ViewerWidget::DragEntered(QDragEnterEvent* event)
+20 -6
View File
@@ -34,7 +34,6 @@
#include "node/output/viewer/viewer.h"
#include "render/previewaudiodevice.h"
#include "render/previewautocacher.h"
#include "threading/threadticketwatcher.h"
#include "viewerdisplay.h"
#include "viewersizer.h"
#include "viewerwindow.h"
@@ -51,6 +50,13 @@ class ViewerWidget : public TimeBasedWidget
{
Q_OBJECT
public:
enum WaveformMode {
kWFAutomatic,
kWFViewerOnly,
kWFWaveformOnly,
kWFViewerAndWaveform
};
ViewerWidget(QWidget* parent = nullptr);
virtual ~ViewerWidget() override;
@@ -157,6 +163,8 @@ protected:
virtual void ConnectNodeEvent(ViewerOutput *) override;
virtual void DisconnectNodeEvent(ViewerOutput *) override;
virtual void ConnectedNodeChangeEvent(ViewerOutput *) override;
virtual void ConnectedWorkAreaChangeEvent(TimelineWorkArea *) override;
virtual void ConnectedMarkersChangeEvent(TimelineMarkerList *) override;
virtual void ScaleChangedEvent(const double& s) override;
@@ -195,9 +203,9 @@ private:
void SetDisplayImage(QVariant frame);
RenderTicketWatcher *RequestNextFrameForQueue(RenderTicketPriority priority = RenderTicketPriority::kNormal, bool increment = true);
RenderTicketWatcher *RequestNextFrameForQueue(bool increment = true);
RenderTicketPtr GetFrame(const rational& t, RenderTicketPriority priority);
RenderTicketPtr GetFrame(const rational& t);
void FinishPlayPreprocess();
@@ -221,7 +229,7 @@ private:
void CloseAudioProcessor();
QStackedWidget* stack_;
void SetWaveformMode(WaveformMode wf);
ViewerSizer* sizer_;
@@ -282,6 +290,8 @@ private:
bool enable_audio_scrubbing_;
WaveformMode waveform_mode_;
private slots:
void PlaybackTimerUpdate();
@@ -297,10 +307,12 @@ private slots:
void SetZoomFromMenu(QAction* action);
void UpdateStack();
void UpdateWaveformViewFromMode();
void ContextMenuSetFullScreen(QAction* action);
void ContextMenuSetPlaybackRes(QAction* action);
void ContextMenuDisableSafeMargins();
void ContextMenuSetSafeMargins();
@@ -315,7 +327,7 @@ private slots:
void ViewerInvalidatedVideoRange(const olive::TimeRange &range);
void ManualSwitchToWaveform(bool e);
void UpdateWaveformModeFromMenu(QAction *a);
void DragEntered(QDragEnterEvent* event);
@@ -336,6 +348,8 @@ private slots:
void CreateAddableAt(const QRectF &f);
void HandleFirstRequeueDestroy();
};
}
+286 -211
View File
@@ -72,8 +72,6 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
{
connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged);
connect(this, &ViewerDisplayWidget::InnerWidgetMouseMove, this, &ViewerDisplayWidget::EmitColorAtCursor);
// Initializes cursor based on tool
UpdateCursor();
@@ -116,7 +114,7 @@ void ViewerDisplayWidget::UpdateCursor()
void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
{
signal_cursor_color_ = e;
inner_widget()->setMouseTracking(e);
SetInnerMouseTracking(e);
}
void ViewerDisplayWidget::SetImage(const QVariant &buffer)
@@ -241,185 +239,53 @@ void ViewerDisplayWidget::IncrementSkippedFrames()
Core::instance()->ShowStatusBarMessage(tr("%n skipped frame(s) detected during playback", nullptr, frames_skipped_), 10000);
}
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
bool ViewerDisplayWidget::eventFilter(QObject *o, QEvent *e)
{
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();
gizmo_last_drag_ = gizmo_start_drag_;
current_gizmo_->SetGlobals(NodeTraverser::GenerateGlobals(gizmo_params_, GenerateGizmoTime()));
} else if (IsHandDrag(event)) {
// Handle hand drag
hand_last_drag_pos_ = event->pos();
hand_dragging_ = true;
emit HandDragStarted();
setCursor(Qt::ClosedHandCursor);
} else {
if (event->button() == Qt::LeftButton) {
// Handle standard drag
emit DragStarted();
}
super::mousePressEvent(event);
if (o != this->inner_widget()) {
return super::eventFilter(o, e);
}
}
void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event)
{
// Handle hand dragging
if (hand_dragging_) {
// Emit movement
emit HandDragMoved(event->x() - hand_last_drag_pos_.x(),
event->y() - hand_last_drag_pos_.y());
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 = gizmo_start_drag_ * gizmo_last_draw_transform_inverted_;
rational gizmo_time = GetGizmoTime();
NodeTraverser t;
t.SetCacheVideoParams(gizmo_params_);
NodeValueRow row = t.GenerateRow(gizmos_, TimeRange(gizmo_time, gizmo_time + gizmo_params_.frame_rate_as_time_base()));
draggable->DragStart(row, start.x(), start.y(), gizmo_time);
gizmo_drag_started_ = true;
}
QPointF v = event->pos() * gizmo_last_draw_transform_inverted_;
switch (draggable->GetDragValueBehavior()) {
case DraggableGizmo::kAbsolute:
// Above value is correct
break;
case DraggableGizmo::kDeltaFromPrevious:
v -= gizmo_last_drag_ * gizmo_last_draw_transform_inverted_;
gizmo_last_drag_ = event->pos();
break;
case DraggableGizmo::kDeltaFromStart:
v -= gizmo_start_drag_ * gizmo_last_draw_transform_inverted_;
break;
}
draggable->DragMove(v.x(), v.y(), event->modifiers());
}
} else {
// Default behavior
super::mouseMoveEvent(event);
}
}
void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (hand_dragging_) {
// Handle hand drag
emit HandDragEnded();
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
if (gizmo_drag_started_) {
MultiUndoCommand *command = new MultiUndoCommand();
if (DraggableGizmo *draggable = dynamic_cast<DraggableGizmo*>(current_gizmo_)) {
draggable->DragEnd(command);
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
gizmo_drag_started_ = false;
}
current_gizmo_ = nullptr;
} else {
// Default behavior
super::mouseReleaseEvent(event);
}
}
void ViewerDisplayWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && gizmos_) {
QPointF ptr = TransformViewerSpaceToBufferSpace(event->pos());
foreach (NodeGizmo *g, gizmos_->GetGizmos()) {
if (TextGizmo *text = dynamic_cast<TextGizmo*>(g)) {
if (text->GetRect().contains(ptr)) {
OpenTextGizmo(text, event);
break;
}
switch (e->type()) {
case QEvent::MouseButtonPress:
{
QMouseEvent *mouse = static_cast<QMouseEvent*>(e);
if (!(mouse->flags() & Qt::MouseEventCreatedDoubleClick)) {
if (OnMousePress(mouse)) {
return true;
}
}
break;
}
case QEvent::MouseMove:
EmitColorAtCursor(static_cast<QMouseEvent*>(e));
if (OnMouseMove(static_cast<QMouseEvent*>(e))) {
return true;
}
break;
case QEvent::MouseButtonRelease:
if (OnMouseRelease(static_cast<QMouseEvent*>(e))) {
return true;
}
break;
case QEvent::MouseButtonDblClick:
if (OnMouseDoubleClick(static_cast<QMouseEvent*>(e))) {
return true;
}
break;
case QEvent::DragEnter:
emit DragEntered(static_cast<QDragEnterEvent*>(e));
break;
case QEvent::DragLeave:
emit DragLeft(static_cast<QDragLeaveEvent*>(e));
break;
case QEvent::Drop:
emit Dropped(static_cast<QDropEvent*>(e));
break;
default:
break;
}
super::mouseDoubleClickEvent(event);
}
void ViewerDisplayWidget::dragEnterEvent(QDragEnterEvent *event)
{
emit DragEntered(event);
if (!event->isAccepted()) {
super::dragEnterEvent(event);
}
}
void ViewerDisplayWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
emit DragLeft(event);
if (!event->isAccepted()) {
super::dragLeaveEvent(event);
}
}
void ViewerDisplayWidget::dropEvent(QDropEvent *event)
{
emit Dropped(event);
if (!event->isAccepted()) {
super::dropEvent(event);
}
return super::eventFilter(o, e);
}
void ViewerDisplayWidget::OnPaint()
@@ -510,7 +376,7 @@ void ViewerDisplayWidget::OnPaint()
TimeRange range = GenerateGizmoTime();
gizmo_db_ = gt.GenerateRow(gizmos_, range);
QPainter p(inner_widget());
QPainter p(paint_device());
gizmo_last_draw_transform_ = GenerateGizmoTransform(gt, range);
p.setWorldTransform(gizmo_last_draw_transform_);
@@ -524,7 +390,7 @@ void ViewerDisplayWidget::OnPaint()
// Draw action/title safe areas
if (safe_margin_.is_enabled()) {
QPainter p(inner_widget());
QPainter p(paint_device());
p.setWorldTransform(GenerateWorldTransform());
p.setPen(QPen(Qt::lightGray, 0));
@@ -574,7 +440,7 @@ void ViewerDisplayWidget::OnPaint()
}
if (frame_rate_average_count_ >= frame_rate_averages_.size()) {
QPainter p(inner_widget());
QPainter p(paint_device());
double average = 0.0;
for (int i=0; i<frame_rate_averages_.size(); i++) {
@@ -582,10 +448,10 @@ void ViewerDisplayWidget::OnPaint()
}
average /= double(frame_rate_averages_.size());
DrawTextWithCrudeShadow(&p, inner_widget()->rect(), tr("%1 FPS").arg(QString::number(average, 'f', 1)));
DrawTextWithCrudeShadow(&p, GetInnerRect(), tr("%1 FPS").arg(QString::number(average, 'f', 1)));
if (frames_skipped_ > 0) {
DrawTextWithCrudeShadow(&p, inner_widget()->rect().adjusted(0, p.fontMetrics().height(), 0, 0),
DrawTextWithCrudeShadow(&p, GetInnerRect().adjusted(0, p.fontMetrics().height(), 0, 0),
tr("%1 frames skipped").arg(frames_skipped_));
}
}
@@ -596,7 +462,7 @@ void ViewerDisplayWidget::OnPaint()
const QVector<Track*> &subtitle_tracklist = subtitle_tracks_->track_list(Track::kSubtitle)->GetTracks();
if (!subtitle_tracklist.empty()) {
QPainter p(inner_widget());
QPainter p(paint_device());
QTransform transform = GenerateWorldTransform();
QRect bounding_box = transform.mapRect(rect());
@@ -641,10 +507,14 @@ void ViewerDisplayWidget::OnPaint()
void ViewerDisplayWidget::OnDestroy()
{
renderer()->DestroyNativeShader(deinterlace_shader_);
deinterlace_shader_.clear();
renderer()->DestroyNativeShader(blank_shader_);
blank_shader_.clear();
if (!deinterlace_shader_.isNull()) {
renderer()->DestroyNativeShader(deinterlace_shader_);
deinterlace_shader_.clear();
}
if (!blank_shader_.isNull()) {
renderer()->DestroyNativeShader(blank_shader_);
blank_shader_.clear();
}
super::OnDestroy();
@@ -790,56 +660,261 @@ void ViewerDisplayWidget::OpenTextGizmo(TextGizmo *text, QMouseEvent *event)
{
QTransform gizmo_transform = GenerateDisplayTransform();
ViewerTextEditor *text_edit = new ViewerTextEditor(gizmo_transform.m11(), this);
// Create popup container for text and toolbar
auto popup = new QWidget(this);
popup->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
popup->setAttribute(Qt::WA_DeleteOnClose);
popup->setAttribute(Qt::WA_TranslucentBackground);
// Create text editor
ViewerTextEditor *text_edit = new ViewerTextEditor(gizmo_transform.m11(), popup);
Html::HtmlToDoc(text_edit->document(), text->GetHtml());
text_edit->setProperty("gizmo", reinterpret_cast<quintptr>(text));
connect(text_edit, &ViewerTextEditor::textChanged, this, &ViewerDisplayWidget::TextEditChanged);
QRectF transformed_geom = gizmo_transform.map(text->GetRect()).boundingRect();
text_edit->setGeometry(transformed_geom.toRect());
// Get on screen text rect (this will be the text editor's global geometry)
QRect global_text_area = gizmo_transform.map(text->GetRect()).boundingRect().toRect();
global_text_area = QRect(mapToGlobal(global_text_area.topLeft()), mapToGlobal(global_text_area.bottomRight()));
ViewerTextEditorToolBar *toolbar = new ViewerTextEditorToolBar(this);
QRect global_popup_area = global_text_area;
QPoint pos = mapToGlobal(QPoint(transformed_geom.x(), transformed_geom.y() - toolbar->height()));
// Create toolbar
ViewerTextEditorToolBar *toolbar = new ViewerTextEditorToolBar(popup);
text_edit->ConnectToolBar(toolbar);
// Work out which corner of the text editor to anchor the toolbar to based on screen limitations
bool top = true;
bool left = true;
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());
// Look for screen that contains text area
if (screen->geometry().contains(global_text_area)) {
if (global_text_area.left() + toolbar->width() > screen->geometry().right()) {
left = false;
}
if (global_text_area.top() - toolbar->height() < screen->geometry().top()) {
top = false;
}
break;
}
}
toolbar->move(pos);
toolbar->show();
text_edit->show();
connect(text_edit, &ViewerTextEditor::textChanged, this, &ViewerDisplayWidget::TextEditChanged);
QPoint toolbar_pos;
text_edit->ConnectToolBar(toolbar);
if (top) {
global_popup_area.adjust(0, -toolbar->height(), 0, 0);
toolbar_pos.setY(0);
} else {
global_popup_area.adjust(0, 0, 0, toolbar->height());
toolbar_pos.setY(global_text_area.height());
}
QPoint text_edit_pos;
if (toolbar->width() > global_popup_area.width()) {
int diff = toolbar->width() - global_popup_area.width();
if (left) {
global_popup_area.adjust(0, 0, diff, 0);
} else {
global_popup_area.adjust(-diff, 0, 0, 0);
}
toolbar_pos.setX(0);
} else {
if (left) {
toolbar_pos.setX(0);
} else {
toolbar_pos.setX(global_popup_area.width() - toolbar->width());
}
}
toolbar->move(toolbar_pos);
popup->setGeometry(global_popup_area);
text_edit->setGeometry(QRect(text_edit->mapFromGlobal(global_text_area.topLeft()), text_edit->mapFromGlobal(global_text_area.bottomRight())));
popup->show();
// Store click pos from event so we can use it later to set the initial text cursor position
QPoint click_pos;
if (event) {
text_edit_pos = text_edit->mapFrom(this, event->pos());
click_pos = event->globalPos();
}
// Ensure text edit is actually focused rather than the toolbar
connect(toolbar, &ViewerTextEditorToolBar::FirstPaint, this, [this, text_edit, text_edit_pos]{
connect(toolbar, &ViewerTextEditorToolBar::FirstPaint, this, [text_edit, click_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));
if (!click_pos.isNull()) {
text_edit->setTextCursor(text_edit->cursorForPosition(text_edit->mapFromGlobal(click_pos)));
}
});
}
bool ViewerDisplayWidget::OnMousePress(QMouseEvent *event)
{
if (IsHandDrag(event)) {
// Handle hand drag
hand_last_drag_pos_ = event->pos();
hand_dragging_ = true;
emit HandDragStarted();
setCursor(Qt::ClosedHandCursor);
return true;
} else if (event->button() == Qt::LeftButton) {
if (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 (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();
gizmo_last_drag_ = gizmo_start_drag_;
current_gizmo_->SetGlobals(NodeTraverser::GenerateGlobals(gizmo_params_, GenerateGizmoTime()));
} else {
// Handle standard drag
emit DragStarted();
}
// 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);
});
return true;
}
return false;
}
bool ViewerDisplayWidget::OnMouseMove(QMouseEvent *event)
{
// Handle hand dragging
if (hand_dragging_) {
// Emit movement
emit HandDragMoved(event->x() - hand_last_drag_pos_.x(),
event->y() - hand_last_drag_pos_.y());
hand_last_drag_pos_ = event->pos();
return true;
} else if (add_band_) {
add_band_->setGeometry(QRect(event->pos(), add_band_start_).normalized());
return true;
} else if (current_gizmo_) {
// Signal movement
if (DraggableGizmo *draggable = dynamic_cast<DraggableGizmo*>(current_gizmo_)) {
if (!gizmo_drag_started_) {
QPointF start = gizmo_start_drag_ * gizmo_last_draw_transform_inverted_;
rational gizmo_time = GetGizmoTime();
NodeTraverser t;
t.SetCacheVideoParams(gizmo_params_);
NodeValueRow row = t.GenerateRow(gizmos_, TimeRange(gizmo_time, gizmo_time + gizmo_params_.frame_rate_as_time_base()));
draggable->DragStart(row, start.x(), start.y(), gizmo_time);
gizmo_drag_started_ = true;
}
QPointF v = event->pos() * gizmo_last_draw_transform_inverted_;
switch (draggable->GetDragValueBehavior()) {
case DraggableGizmo::kAbsolute:
// Above value is correct
break;
case DraggableGizmo::kDeltaFromPrevious:
v -= gizmo_last_drag_ * gizmo_last_draw_transform_inverted_;
gizmo_last_drag_ = event->pos();
break;
case DraggableGizmo::kDeltaFromStart:
v -= gizmo_start_drag_ * gizmo_last_draw_transform_inverted_;
break;
}
draggable->DragMove(v.x(), v.y(), event->modifiers());
return true;
}
}
return false;
}
bool ViewerDisplayWidget::OnMouseRelease(QMouseEvent *e)
{
if (hand_dragging_) {
// Handle hand drag
emit HandDragEnded();
hand_dragging_ = false;
UpdateCursor();
return true;
} 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;
return true;
} else if (current_gizmo_) {
// Handle gizmo
if (gizmo_drag_started_) {
MultiUndoCommand *command = new MultiUndoCommand();
if (DraggableGizmo *draggable = dynamic_cast<DraggableGizmo*>(current_gizmo_)) {
draggable->DragEnd(command);
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
gizmo_drag_started_ = false;
}
current_gizmo_ = nullptr;
return true;
}
return false;
}
bool ViewerDisplayWidget::OnMouseDoubleClick(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && gizmos_) {
QPointF ptr = TransformViewerSpaceToBufferSpace(event->pos());
foreach (NodeGizmo *g, gizmos_->GetGizmos()) {
if (TextGizmo *text = dynamic_cast<TextGizmo*>(g)) {
if (text->GetRect().contains(ptr)) {
OpenTextGizmo(text, event);
return true;
}
}
}
}
return false;
}
void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e)
+9 -27
View File
@@ -22,7 +22,6 @@
#define VIEWERGLWIDGET_H
#include <QMatrix4x4>
#include <QOpenGLWidget>
#include <QRubberBand>
#include "node/color/colormanager/colormanager.h"
@@ -131,6 +130,8 @@ public:
return &timer_;
}
virtual bool eventFilter(QObject *o, QEvent *e) override;
public slots:
/**
* @brief Set the transformation matrix to draw with
@@ -216,30 +217,6 @@ signals:
void CreateAddableAt(const QRectF &rect);
protected:
/**
* @brief Override the mouse press event for the DragStarted() signal and gizmos
*/
virtual void mousePressEvent(QMouseEvent* event) override;
/**
* @brief Override mouse move to signal for the pixel sampler and gizmos
*/
virtual void mouseMoveEvent(QMouseEvent* event) override;
/**
* @brief Override mouse release event for gizmos
*/
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
virtual void dragEnterEvent(QDragEnterEvent* event) override;
virtual void dragLeaveEvent(QDragLeaveEvent* event) override;
virtual void dropEvent(QDropEvent* event) override;
protected slots:
/**
* @brief Paint function to display the texture (received in SetTexture()) on screen.
@@ -279,6 +256,13 @@ private:
void OpenTextGizmo(TextGizmo *text, QMouseEvent *event = nullptr);
bool OnMousePress(QMouseEvent *e);
bool OnMouseMove(QMouseEvent *e);
bool OnMouseRelease(QMouseEvent *e);
bool OnMouseDoubleClick(QMouseEvent *e);
void EmitColorAtCursor(QMouseEvent* e);
/**
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
*/
@@ -391,8 +375,6 @@ private:
bool queue_starved_;
private slots:
void EmitColorAtCursor(QMouseEvent* e);
void UpdateFromQueue();
void TextEditChanged();
+8 -45
View File
@@ -61,7 +61,6 @@ ViewerTextEditor::ViewerTextEditor(double scale, QWidget *parent) :
dpi_force_.setDotsPerMeterY(dpm);
document()->documentLayout()->setPaintDevice(&dpi_force_);
connect(qApp, &QApplication::focusChanged, this, &ViewerTextEditor::FocusChanged);
connect(this, &QTextEdit::currentCharFormatChanged, this, &ViewerTextEditor::FormatChanged);
connect(document(), &QTextDocument::contentsChanged, this, &ViewerTextEditor::DocumentChanged, Qt::QueuedConnection);
@@ -70,8 +69,6 @@ ViewerTextEditor::ViewerTextEditor(double scale, QWidget *parent) :
void ViewerTextEditor::ConnectToolBar(ViewerTextEditorToolBar *toolbar)
{
connect(this, &ViewerTextEditor::destroyed, toolbar, &ViewerTextEditorToolBar::deleteLater);
connect(toolbar, &ViewerTextEditorToolBar::FamilyChanged, this, &ViewerTextEditor::SetFamily);
connect(toolbar, &ViewerTextEditorToolBar::SizeChanged, this, &ViewerTextEditor::setFontPointSize);
connect(toolbar, &ViewerTextEditorToolBar::StyleChanged, this, &ViewerTextEditor::SetStyle);
@@ -94,15 +91,6 @@ void ViewerTextEditor::ConnectToolBar(ViewerTextEditorToolBar *toolbar)
toolbars_.append(toolbar);
}
void ViewerTextEditor::keyPressEvent(QKeyEvent *event)
{
super::keyPressEvent(event);
if (event->key() == Qt::Key_Escape) {
deleteLater();
}
}
void ViewerTextEditor::paintEvent(QPaintEvent *e)
{
QPainter p(this->viewport());
@@ -134,7 +122,9 @@ void ViewerTextEditor::paintEvent(QPaintEvent *e)
ctx.selections.append(selection);
}
transparent_clone_->documentLayout()->draw(&p, ctx);
if (transparent_clone_) {
transparent_clone_->documentLayout()->draw(&p, ctx);
}
}
void ViewerTextEditor::UpdateToolBar(ViewerTextEditorToolBar *toolbar, const QTextCharFormat &f, const QTextBlockFormat &b, Qt::Alignment alignment)
@@ -176,34 +166,6 @@ void ViewerTextEditor::UpdateToolBar(ViewerTextEditorToolBar *toolbar, const QTe
toolbar->SetLineHeight(b.lineHeight() == 0.0 ? 100 : b.lineHeight());
}
void ViewerTextEditor::FocusChanged(QWidget *old, QWidget *now)
{
if (!listen_to_focus_events_) {
return;
}
QWidget *test = now;
if (!test) {
// Ignore null focuses because that could be one of the toolbar widgets simply losing focus
// and that would be undesirable to close the text editor from
return;
}
while (test) {
if (test == this
|| dynamic_cast<ViewerTextEditorToolBar*>(test)
|| dynamic_cast<SliderLadder*>(test)) {
return;
}
test = test->parentWidget();
}
// If we didn't return in the loop, the user must have focused on something else
deleteLater();
}
void ViewerTextEditor::FormatChanged(const QTextCharFormat &f)
{
if (!block_update_toolbar_signal_) {
@@ -323,8 +285,9 @@ void ViewerTextEditor::DocumentChanged()
}
ViewerTextEditorToolBar::ViewerTextEditorToolBar(QWidget *parent) :
QWidget(parent, Qt::Tool | Qt::FramelessWindowHint),
painted_(false)
QWidget(parent),
painted_(false),
drag_enabled_(false)
{
QVBoxLayout *outer_layout = new QVBoxLayout(this);
outer_layout->setSpacing(0);
@@ -509,7 +472,7 @@ void ViewerTextEditorToolBar::mousePressEvent(QMouseEvent *event)
{
QWidget::mousePressEvent(event);
if (event->button() == Qt::LeftButton) {
if (event->button() == Qt::LeftButton && drag_enabled_) {
drag_anchor_ = event->pos();
}
}
@@ -518,7 +481,7 @@ void ViewerTextEditorToolBar::mouseMoveEvent(QMouseEvent *event)
{
QWidget::mouseMoveEvent(event);
if (event->buttons() & Qt::LeftButton) {
if ((event->buttons() & Qt::LeftButton) && drag_enabled_) {
this->move(mapToParent(QPoint(event->pos() - drag_anchor_)));
}
}
+2 -4
View File
@@ -126,6 +126,8 @@ private:
bool painted_;
bool drag_enabled_;
private slots:
void UpdateFontStyleList(const QString &family);
@@ -144,8 +146,6 @@ public:
void SetListenToFocusEvents(bool e) { listen_to_focus_events_ = e; }
protected:
virtual void keyPressEvent(QKeyEvent *event) override;
virtual void paintEvent(QPaintEvent *event) override;
private:
@@ -166,8 +166,6 @@ private:
bool listen_to_focus_events_;
private slots:
void FocusChanged(QWidget *old, QWidget *now);
void FormatChanged(const QTextCharFormat &f);
void SetFamily(const QString &s);