@@ -151,6 +151,10 @@ void AudioVisualWaveform::Shift(const rational &from, const rational &to)
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index > data_.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (from_index > to_index) {
|
||||
// Shifting backwards <-
|
||||
int copy_sz = data_.size() - from_index;
|
||||
|
||||
@@ -59,6 +59,11 @@ ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) cons
|
||||
return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/crossdissolve.frag"), QString());
|
||||
}
|
||||
|
||||
void CrossDissolveTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const
|
||||
{
|
||||
job.SetAlphaChannelRequired(true);
|
||||
}
|
||||
|
||||
void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const
|
||||
{
|
||||
for (int i=0; i<out_samples->sample_count(); i++) {
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
virtual ShaderCode GetShaderCode(const QString& shader_id) const override;
|
||||
|
||||
protected:
|
||||
virtual void ShaderJobEvent(NodeValueDatabase& value, ShaderJob& job) const override;
|
||||
|
||||
virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const override;
|
||||
|
||||
};
|
||||
|
||||
@@ -83,6 +83,10 @@ NodeValueTable TransformDistortNode::Value(NodeValueDatabase &value) const
|
||||
job.InsertValue(QStringLiteral("ove_mvpmat"), ShaderValue(real_matrix, NodeParam::kMatrix));
|
||||
job.SetInterpolation(QStringLiteral("ove_maintex"), static_cast<Texture::Interpolation>(value[interpolation_input_].Get(NodeParam::kCombo).toInt()));
|
||||
|
||||
// FIXME: This should be optimized, we can use matrix math to determine if this operation will
|
||||
// end up with gaps in the screen that will require an alpha channel.
|
||||
job.SetAlphaChannelRequired(true);
|
||||
|
||||
table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
||||
OpenGLRenderer::~OpenGLRenderer()
|
||||
{
|
||||
Destroy();
|
||||
PostDestroy();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::Init(QOpenGLContext *existing_ctx)
|
||||
@@ -114,6 +115,14 @@ bool OpenGLRenderer::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::PostDestroy()
|
||||
{
|
||||
// Destroy surface if we created it
|
||||
if (surface_.isValid()) {
|
||||
surface_.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::PostInit()
|
||||
{
|
||||
// Make context current on that surface
|
||||
@@ -142,11 +151,6 @@ void OpenGLRenderer::DestroyInternal()
|
||||
delete context_;
|
||||
}
|
||||
context_ = nullptr;
|
||||
|
||||
// Destroy surface if we created it
|
||||
if (surface_.isValid()) {
|
||||
surface_.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ public:
|
||||
|
||||
virtual bool Init() override;
|
||||
|
||||
virtual void PostDestroy() override;
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() override;
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
|
||||
void Destroy();
|
||||
|
||||
virtual void PostDestroy() = 0;
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() = 0;
|
||||
|
||||
|
||||
@@ -58,12 +58,14 @@ void RendererThreadWrapper::DestroyInternal()
|
||||
{
|
||||
if (thread_) {
|
||||
QMetaObject::invokeMethod(inner_, "DestroyInternal", Qt::BlockingQueuedConnection);
|
||||
inner_ = nullptr;
|
||||
|
||||
thread_->quit();
|
||||
thread_->wait();
|
||||
delete thread_;
|
||||
thread_ = nullptr;
|
||||
|
||||
// Destroy in main thread
|
||||
inner_->PostDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,14 @@ public:
|
||||
virtual ~RendererThreadWrapper() override
|
||||
{
|
||||
Destroy();
|
||||
PostDestroy();
|
||||
delete inner_;
|
||||
}
|
||||
|
||||
virtual bool Init() override;
|
||||
|
||||
virtual void PostDestroy() override {}
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() override;
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ RenderManager::~RenderManager()
|
||||
delete still_cache_;
|
||||
|
||||
context_->Destroy();
|
||||
context_->PostDestroy();
|
||||
delete context_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,11 +270,12 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
|
||||
|
||||
ColorManager* color_manager = Node::ValueToPtr<ColorManager>(ticket_->property("colormanager"));
|
||||
|
||||
// Calculate footage divider that still fits in the divider chosen
|
||||
int footage_divider = 1;
|
||||
while (VideoParams::GetScaledDimension(video_stream->width(), footage_divider) > video_params.effective_width()
|
||||
|| VideoParams::GetScaledDimension(video_stream->height(), footage_divider) > video_params.effective_height()) {
|
||||
footage_divider++;
|
||||
// See if we can make this divider larger (i.e. if the fooage is smaller)
|
||||
int footage_divider = video_params.divider();
|
||||
while (footage_divider > 1
|
||||
&& VideoParams::GetScaledDimension(video_stream->width(), footage_divider-1) < video_params.effective_width()
|
||||
&& VideoParams::GetScaledDimension(video_stream->height(), footage_divider-1) < video_params.effective_height()) {
|
||||
footage_divider--;
|
||||
}
|
||||
|
||||
StillImageCache::EntryPtr want_entry = std::make_shared<StillImageCache::Entry>(
|
||||
|
||||
+840
-726
File diff suppressed because it is too large
Load Diff
@@ -89,7 +89,6 @@ CurveWidget::CurveWidget(QWidget *parent) :
|
||||
ruler_view_layout->addWidget(ruler());
|
||||
|
||||
view_ = new CurveView();
|
||||
connect(view_, &CurveView::RequestCenterScrollOnPlayhead, this, &CurveWidget::CenterScrollOnPlayhead);
|
||||
ConnectTimelineView(view_);
|
||||
ruler_view_layout->addWidget(view_);
|
||||
|
||||
|
||||
@@ -208,6 +208,7 @@ void ManagedDisplayWidget::MenuColorspaceSelect(QAction *action)
|
||||
void ManagedDisplayWidget::OnDestroy()
|
||||
{
|
||||
attached_renderer_->Destroy();
|
||||
attached_renderer_->PostDestroy();
|
||||
}
|
||||
|
||||
void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform)
|
||||
|
||||
@@ -85,7 +85,6 @@ NodeParamView::NodeParamView(QWidget *parent) :
|
||||
keyframe_view_ = new KeyframeView();
|
||||
keyframe_view_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
ConnectTimelineView(keyframe_view_);
|
||||
connect(keyframe_view_, &KeyframeView::RequestCenterScrollOnPlayhead, this, &NodeParamView::CenterScrollOnPlayhead);
|
||||
keyframe_area_layout->addWidget(keyframe_view_);
|
||||
|
||||
// Connect ruler and keyframe view together
|
||||
|
||||
@@ -35,6 +35,7 @@ NodeParamViewRichText::NodeParamViewRichText(QWidget *parent) :
|
||||
layout->setMargin(0);
|
||||
|
||||
line_edit_ = new QTextEdit();
|
||||
line_edit_->setUndoRedoEnabled(true);
|
||||
connect(line_edit_, &QTextEdit::textChanged, this, &NodeParamViewRichText::InnerWidgetTextChanged);
|
||||
layout->addWidget(line_edit_);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QInputDialog>
|
||||
#include <QUndoCommand>
|
||||
|
||||
#include "common/autoscroll.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "config/config.h"
|
||||
#include "core.h"
|
||||
@@ -155,6 +156,22 @@ void TimeBasedWidget::ScrollBarResized(const double &multiplier)
|
||||
SetScale(GetScale() * corrected_scale);
|
||||
}
|
||||
|
||||
void TimeBasedWidget::PageScrollToPlayhead()
|
||||
{
|
||||
int playhead_pos = qRound(TimeToScene(GetTime()));
|
||||
|
||||
int viewport_width = ruler()->width();
|
||||
int viewport_padding = viewport_width / 16;
|
||||
|
||||
if (playhead_pos < scrollbar()->value()) {
|
||||
// Anchor the playhead to the RIGHT of where we scroll to
|
||||
scrollbar()->setValue(playhead_pos - viewport_width + viewport_padding);
|
||||
} else if (playhead_pos > scrollbar()->value() + viewport_width) {
|
||||
// Anchor the playhead to the LEFT of where we scroll to
|
||||
scrollbar()->setValue(playhead_pos - viewport_padding);
|
||||
}
|
||||
}
|
||||
|
||||
TimeRuler *TimeBasedWidget::ruler() const
|
||||
{
|
||||
return ruler_;
|
||||
@@ -224,6 +241,18 @@ void TimeBasedWidget::SetTimestamp(int64_t timestamp)
|
||||
{
|
||||
ruler_->SetTime(timestamp);
|
||||
|
||||
switch (static_cast<AutoScroll::Method>(Config::Current()["Autoscroll"].toInt())) {
|
||||
case AutoScroll::kNone:
|
||||
// Do nothing
|
||||
break;
|
||||
case AutoScroll::kPage:
|
||||
QMetaObject::invokeMethod(this, "PageScrollToPlayhead", Qt::QueuedConnection);
|
||||
break;
|
||||
case AutoScroll::kSmooth:
|
||||
QMetaObject::invokeMethod(this, "CenterScrollOnPlayhead", Qt::QueuedConnection);
|
||||
break;
|
||||
}
|
||||
|
||||
TimeChangedEvent(timestamp);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,14 @@ private slots:
|
||||
|
||||
void ScrollBarResized(const double& multiplier);
|
||||
|
||||
/**
|
||||
* @brief Slot to handle page scrolling of the playhead
|
||||
*
|
||||
* If the playhead is outside the current scroll bounds, this function will scroll to where it is. Otherwise it will
|
||||
* do nothing.
|
||||
*/
|
||||
void PageScrollToPlayhead();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "tool/edit.h"
|
||||
#include "tool/pointer.h"
|
||||
#include "tool/razor.h"
|
||||
#include "tool/record.h"
|
||||
#include "tool/ripple.h"
|
||||
#include "tool/rolling.h"
|
||||
#include "tool/slide.h"
|
||||
@@ -96,7 +97,7 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
tools_.replace(olive::Tool::kSlide, new SlideTool(this));
|
||||
tools_.replace(olive::Tool::kZoom, new ZoomTool(this));
|
||||
tools_.replace(olive::Tool::kTransition, new TransitionTool(this));
|
||||
//tools_.replace(olive::Tool::kRecord, new PointerTool(this)); FIXME: Implement
|
||||
tools_.replace(olive::Tool::kRecord, new RecordTool(this));
|
||||
tools_.replace(olive::Tool::kAdd, new AddTool(this));
|
||||
|
||||
import_tool_ = new ImportTool(this);
|
||||
@@ -131,7 +132,6 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
connect(view, &TimelineView::customContextMenuRequested, this, &TimelineWidget::ShowContextMenu);
|
||||
connect(scrollbar(), &QScrollBar::valueChanged, view->horizontalScrollBar(), &QScrollBar::setValue);
|
||||
connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, scrollbar(), &QScrollBar::setValue);
|
||||
connect(view, &TimelineView::RequestCenterScrollOnPlayhead, this, &TimelineWidget::CenterScrollOnPlayhead);
|
||||
|
||||
connect(view, &TimelineView::MousePressed, this, &TimelineWidget::ViewMousePressed);
|
||||
connect(view, &TimelineView::MouseMoved, this, &TimelineWidget::ViewMouseMoved);
|
||||
@@ -299,7 +299,7 @@ void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n)
|
||||
void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata)
|
||||
{
|
||||
// Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere
|
||||
QList<TimelineViewBlockItem*>& selected = *static_cast<QList<TimelineViewBlockItem*>*>(userdata);
|
||||
QVector<TimelineViewBlockItem*>& selected = *static_cast<QVector<TimelineViewBlockItem*>*>(userdata);
|
||||
rational earliest_in = RATIONAL_MAX;
|
||||
|
||||
foreach (TimelineViewBlockItem* item, selected) {
|
||||
@@ -329,7 +329,7 @@ void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void
|
||||
|
||||
void TimelineWidget::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData& xml_node_data, void *userdata)
|
||||
{
|
||||
QList<BlockPasteData>& paste_data = *static_cast<QList<BlockPasteData>*>(userdata);
|
||||
QVector<BlockPasteData>& paste_data = *static_cast<QVector<BlockPasteData>*>(userdata);
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("block")) {
|
||||
@@ -354,14 +354,6 @@ void TimelineWidget::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, X
|
||||
}
|
||||
}
|
||||
|
||||
rational TimelineWidget::GetToolTipTimebase() const
|
||||
{
|
||||
if (GetConnectedNode() && use_audio_time_units_) {
|
||||
return GetConnectedNode()->audio_params().time_base();
|
||||
}
|
||||
return timebase();
|
||||
}
|
||||
|
||||
void TimelineWidget::SelectAll()
|
||||
{
|
||||
QVector<Block*> newly_selected_blocks;
|
||||
@@ -1212,6 +1204,11 @@ TimelineView *TimelineWidget::GetFirstTimelineView()
|
||||
return views_.first()->view();
|
||||
}
|
||||
|
||||
rational TimelineWidget::GetTimebaseForTrackType(Timeline::TrackType type)
|
||||
{
|
||||
return views_.at(type)->view()->timebase();
|
||||
}
|
||||
|
||||
const QRect& TimelineWidget::GetRubberBandGeometry() const
|
||||
{
|
||||
return rubberband_.geometry();
|
||||
|
||||
@@ -154,8 +154,6 @@ public:
|
||||
return !ghost_items_.isEmpty();
|
||||
}
|
||||
|
||||
rational GetToolTipTimebase() const;
|
||||
|
||||
bool IsBlockSelected(Block* b) const
|
||||
{
|
||||
return selected_blocks_.contains(b);
|
||||
@@ -167,6 +165,8 @@ public:
|
||||
|
||||
TimelineView* GetFirstTimelineView();
|
||||
|
||||
rational GetTimebaseForTrackType(Timeline::TrackType type);
|
||||
|
||||
const QRect &GetRubberBandGeometry() const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,8 @@ set(OLIVE_SOURCES
|
||||
widget/timelinewidget/tool/pointer.h
|
||||
widget/timelinewidget/tool/razor.cpp
|
||||
widget/timelinewidget/tool/razor.h
|
||||
widget/timelinewidget/tool/record.cpp
|
||||
widget/timelinewidget/tool/record.h
|
||||
widget/timelinewidget/tool/ripple.cpp
|
||||
widget/timelinewidget/tool/ripple.h
|
||||
widget/timelinewidget/tool/rolling.cpp
|
||||
|
||||
@@ -149,9 +149,10 @@ void ImportTool::DragMove(TimelineViewMouseEvent *event)
|
||||
}
|
||||
|
||||
// Generate tooltip (showing earliest in point of imported clip)
|
||||
int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, parent()->GetToolTipTimebase());
|
||||
rational tooltip_timebase = parent()->GetTimebaseForTrackType(event->GetTrack().type());
|
||||
int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, tooltip_timebase);
|
||||
QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp,
|
||||
parent()->GetToolTipTimebase(),
|
||||
tooltip_timebase,
|
||||
Core::instance()->GetTimecodeDisplay());
|
||||
|
||||
// Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way
|
||||
@@ -271,6 +272,12 @@ void ImportTool::FootageToGhosts(rational ghost_start, const QList<DraggedFootag
|
||||
footage_duration = Config::Current()["DefaultStillLength"].value<rational>();
|
||||
}
|
||||
|
||||
// Snap footage duration to timebase
|
||||
rational snap_mvmt = SnapMovementToTimebase(footage_duration, 0, dest_tb);
|
||||
if (!snap_mvmt.isNull()) {
|
||||
footage_duration += snap_mvmt;
|
||||
}
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, footage_ghosts) {
|
||||
ghost->SetIn(ghost_start);
|
||||
ghost->SetOut(ghost_start + footage_duration);
|
||||
|
||||
@@ -469,7 +469,7 @@ void PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos)
|
||||
}
|
||||
|
||||
// Validate ghosts that are being moved (clips from other track types do NOT get moved)
|
||||
{
|
||||
if (track_movement != 0) {
|
||||
QVector<TimelineViewGhostItem*> validate_track_ghosts = parent()->GetGhostItems();
|
||||
for (int i=0;i<validate_track_ghosts.size();i++) {
|
||||
if (validate_track_ghosts.at(i)->GetTrack().type() != drag_track_type_) {
|
||||
@@ -508,10 +508,11 @@ void PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos)
|
||||
|
||||
// Regenerate tooltip and force it to update (otherwise the tooltip won't move as written in the
|
||||
// documentation, and could get in the way of the cursor)
|
||||
rational tooltip_timebase = parent()->GetTimebaseForTrackType(drag_start_.GetTrack().type());
|
||||
QToolTip::hideText();
|
||||
QToolTip::showText(QCursor::pos(),
|
||||
Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, parent()->GetToolTipTimebase()),
|
||||
parent()->GetToolTipTimebase(),
|
||||
Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, tooltip_timebase),
|
||||
tooltip_timebase,
|
||||
Core::instance()->GetTimecodeDisplay(),
|
||||
true),
|
||||
parent());
|
||||
@@ -872,6 +873,8 @@ bool PointerTool::AddMovingTransitionsToClipGhost(Block* block,
|
||||
|
||||
rational PointerTool::ValidateInTrimming(rational movement)
|
||||
{
|
||||
bool first_ghost = true;
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->GetGhostItems()) {
|
||||
if (ghost->GetMode() != Timeline::kTrimIn) {
|
||||
continue;
|
||||
@@ -880,8 +883,11 @@ rational PointerTool::ValidateInTrimming(rational movement)
|
||||
rational earliest_in = RATIONAL_MIN;
|
||||
rational latest_in = ghost->GetOut();
|
||||
|
||||
rational ghost_timebase = parent()->GetTimebaseForTrackType(ghost->GetTrack().type());
|
||||
|
||||
// If the ghost must be at least one frame in size, limit the latest allowed in point
|
||||
if (!ghost->CanHaveZeroLength()) {
|
||||
latest_in -= parent()->timebase();
|
||||
latest_in -= ghost_timebase;
|
||||
}
|
||||
|
||||
// Clamp adjusted value between the earliest and latest values
|
||||
@@ -891,6 +897,11 @@ rational PointerTool::ValidateInTrimming(rational movement)
|
||||
if (clamped != adjusted) {
|
||||
movement = clamped - ghost->GetIn();
|
||||
}
|
||||
|
||||
if (first_ghost) {
|
||||
movement = SnapMovementToTimebase(ghost->GetIn(), movement, ghost_timebase);
|
||||
first_ghost = false;
|
||||
}
|
||||
}
|
||||
|
||||
return movement;
|
||||
@@ -898,6 +909,8 @@ rational PointerTool::ValidateInTrimming(rational movement)
|
||||
|
||||
rational PointerTool::ValidateOutTrimming(rational movement)
|
||||
{
|
||||
bool first_ghost = true;
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->GetGhostItems()) {
|
||||
if (ghost->GetMode() != Timeline::kTrimOut) {
|
||||
continue;
|
||||
@@ -906,8 +919,10 @@ rational PointerTool::ValidateOutTrimming(rational movement)
|
||||
// Determine earliest and latest out points
|
||||
rational earliest_out = ghost->GetIn();
|
||||
|
||||
rational ghost_timebase = parent()->GetTimebaseForTrackType(ghost->GetTrack().type());
|
||||
|
||||
if (!ghost->CanHaveZeroLength()) {
|
||||
earliest_out += parent()->timebase();
|
||||
earliest_out += ghost_timebase;
|
||||
}
|
||||
|
||||
rational latest_out = RATIONAL_MAX;
|
||||
@@ -919,6 +934,11 @@ rational PointerTool::ValidateOutTrimming(rational movement)
|
||||
if (clamped != adjusted) {
|
||||
movement = clamped - ghost->GetOut();
|
||||
}
|
||||
|
||||
if (first_ghost) {
|
||||
movement = SnapMovementToTimebase(ghost->GetOut(), movement, ghost_timebase);
|
||||
first_ghost = false;
|
||||
}
|
||||
}
|
||||
|
||||
return movement;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "record.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
RecordTool::RecordTool(TimelineWidget *parent) :
|
||||
BeamTool(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2020 Olive Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef RECORDTIMELINETOOL_H
|
||||
#define RECORDTIMELINETOOL_H
|
||||
|
||||
#include "beam.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class RecordTool : public BeamTool
|
||||
{
|
||||
public:
|
||||
RecordTool(TimelineWidget* parent);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // RECORDTOOL_H
|
||||
@@ -54,10 +54,11 @@ void SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos)
|
||||
|
||||
// Generate tooltip and force it to to update (otherwise the tooltip won't move as written in the
|
||||
// documentation, and could get in the way of the cursor)
|
||||
rational tooltip_timebase = parent()->GetTimebaseForTrackType(drag_start_.GetTrack().type());
|
||||
QToolTip::hideText();
|
||||
QToolTip::showText(QCursor::pos(),
|
||||
Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, parent()->GetToolTipTimebase()),
|
||||
parent()->GetToolTipTimebase(),
|
||||
Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, tooltip_timebase),
|
||||
tooltip_timebase,
|
||||
Core::instance()->GetTimecodeDisplay(),
|
||||
true),
|
||||
parent());
|
||||
|
||||
@@ -53,8 +53,22 @@ Timeline::MovementMode TimelineTool::FlipTrimMode(const Timeline::MovementMode &
|
||||
return trim_mode;
|
||||
}
|
||||
|
||||
rational TimelineTool::SnapMovementToTimebase(const rational &start, rational movement, const rational &timebase)
|
||||
{
|
||||
rational proposed_position = start + movement;
|
||||
rational snapped = Timecode::snap_time_to_timebase(proposed_position, timebase);
|
||||
|
||||
if (proposed_position != snapped) {
|
||||
movement += snapped - proposed_position;
|
||||
}
|
||||
|
||||
return movement;
|
||||
}
|
||||
|
||||
rational TimelineTool::ValidateTimeMovement(rational movement)
|
||||
{
|
||||
bool first_ghost = true;
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, parent()->GetGhostItems()) {
|
||||
if (ghost->GetMode() != Timeline::kMove) {
|
||||
continue;
|
||||
@@ -63,6 +77,11 @@ rational TimelineTool::ValidateTimeMovement(rational movement)
|
||||
// Prevents any ghosts from going below 0:00:00 time
|
||||
if (ghost->GetIn() + movement < 0) {
|
||||
movement = -ghost->GetIn();
|
||||
} else if (first_ghost) {
|
||||
// Ensure ghost is snapped to a grid
|
||||
movement = SnapMovementToTimebase(ghost->GetIn(), movement, parent()->GetTimebaseForTrackType(ghost->GetTrack().type()));
|
||||
|
||||
first_ghost = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
|
||||
static Timeline::MovementMode FlipTrimMode(const Timeline::MovementMode& trim_mode);
|
||||
|
||||
static rational SnapMovementToTimebase(const rational& start, rational movement, const rational& timebase);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Validates Ghosts that are moving horizontally (time-based)
|
||||
|
||||
@@ -165,6 +165,7 @@ TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(TrackOutput *track, r
|
||||
in_(in),
|
||||
out_(out),
|
||||
splice_(false),
|
||||
splice_split_command_(nullptr),
|
||||
trim_out_(nullptr),
|
||||
trim_in_(nullptr),
|
||||
insert_(nullptr)
|
||||
@@ -305,7 +306,6 @@ void TrackRippleRemoveAreaCommand::undo_internal()
|
||||
trim_out_->set_length_and_media_out(trim_out_old_length_);
|
||||
|
||||
splice_split_command_->undo();
|
||||
delete splice_split_command_;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -344,6 +344,11 @@ void TrackRippleRemoveAreaCommand::undo_internal()
|
||||
|
||||
track_->Node::InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX),
|
||||
track_->block_input(), track_->block_input());
|
||||
|
||||
if (splice_split_command_) {
|
||||
delete splice_split_command_;
|
||||
splice_split_command_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TrackPlaceBlockCommand::TrackPlaceBlockCommand(TrackList *timeline, int track, Block *block, rational in, QUndoCommand *parent) :
|
||||
|
||||
@@ -115,13 +115,14 @@ void TimelineView::wheelEvent(QWheelEvent *event)
|
||||
return;
|
||||
} else {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
|
||||
|
||||
QPoint angle_delta = event->angleDelta();
|
||||
|
||||
if (Config::Current()["InvertTimelineScrollAxes"].toBool()) {
|
||||
if (Config::Current()["InvertTimelineScrollAxes"].toBool() // Check if config is set to invert timeline axes
|
||||
&& event->source() != Qt::MouseEventSynthesizedBySystem) { // Never flip axes on Apple trackpads though
|
||||
angle_delta = QPoint(angle_delta.y(), angle_delta.x());
|
||||
}
|
||||
|
||||
|
||||
QWheelEvent e(
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
event->position(),
|
||||
@@ -255,7 +256,8 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect)
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
foreach (TimelineViewGhostItem* ghost, (*ghosts_)) {
|
||||
if (ghost->GetTrack().type() == connected_track_list_->type()) {
|
||||
if (ghost->GetTrack().type() == connected_track_list_->type()
|
||||
&& !ghost->IsInvisible()) {
|
||||
int track_index = ghost->GetAdjustedTrack().index();
|
||||
|
||||
painter->drawRect(TimeToScene(ghost->GetAdjustedIn()),
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <QScrollBar>
|
||||
#include <QTimer>
|
||||
|
||||
#include "common/autoscroll.h"
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "config/config.h"
|
||||
|
||||
@@ -115,18 +114,6 @@ void TimelineViewBase::SetTime(const int64_t time)
|
||||
{
|
||||
playhead_ = time;
|
||||
|
||||
switch (static_cast<AutoScroll::Method>(Config::Current()["Autoscroll"].toInt())) {
|
||||
case AutoScroll::kNone:
|
||||
// Do nothing
|
||||
break;
|
||||
case AutoScroll::kPage:
|
||||
QMetaObject::invokeMethod(this, "PageScrollToPlayhead", Qt::QueuedConnection);
|
||||
break;
|
||||
case AutoScroll::kSmooth:
|
||||
emit RequestCenterScrollOnPlayhead();
|
||||
break;
|
||||
}
|
||||
|
||||
// Force redraw for playhead
|
||||
viewport()->update();
|
||||
}
|
||||
@@ -257,21 +244,6 @@ void TimelineViewBase::UpdateSceneRect()
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineViewBase::PageScrollToPlayhead()
|
||||
{
|
||||
int playhead_pos = qRound(GetPlayheadX());
|
||||
|
||||
int viewport_padding = viewport()->width() / 16;
|
||||
|
||||
if (playhead_pos < horizontalScrollBar()->value()) {
|
||||
// Anchor the playhead to the RIGHT of where we scroll to
|
||||
horizontalScrollBar()->setValue(playhead_pos - viewport()->width() + viewport_padding);
|
||||
} else if (playhead_pos > horizontalScrollBar()->value() + viewport()->width()) {
|
||||
// Anchor the playhead to the LEFT of where we scroll to
|
||||
horizontalScrollBar()->setValue(playhead_pos - viewport_padding);
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineViewBase::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QGraphicsView::resizeEvent(event);
|
||||
|
||||
@@ -60,8 +60,6 @@ signals:
|
||||
|
||||
void ScaleChanged(double scale);
|
||||
|
||||
void RequestCenterScrollOnPlayhead();
|
||||
|
||||
protected:
|
||||
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
|
||||
|
||||
@@ -124,14 +122,6 @@ private slots:
|
||||
*/
|
||||
void UpdateSceneRect();
|
||||
|
||||
/**
|
||||
* @brief Slot to handle page scrolling of the playhead
|
||||
*
|
||||
* If the playhead is outside the current scroll bounds, this function will scroll to where it is. Otherwise it will
|
||||
* do nothing.
|
||||
*/
|
||||
void PageScrollToPlayhead();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -74,17 +74,6 @@ void TimelineViewGhostItem::SetCanMoveTracks(bool e)
|
||||
can_move_tracks_ = e;
|
||||
}
|
||||
|
||||
/*void TimelineViewGhostItem::SetInvisible(bool invisible)
|
||||
{
|
||||
setBrush(Qt::NoBrush);
|
||||
|
||||
if (invisible) {
|
||||
setPen(Qt::NoPen);
|
||||
} else {
|
||||
setPen(QPen(Qt::yellow, 2)); // FIXME: Make customizable via CSS
|
||||
}
|
||||
}*/
|
||||
|
||||
const rational &TimelineViewGhostItem::GetIn() const
|
||||
{
|
||||
return in_;
|
||||
|
||||
@@ -38,7 +38,14 @@ QVariant GizmoTraverser::ProcessShader(const Node *node, const TimeRange &range,
|
||||
Q_UNUSED(range)
|
||||
Q_UNUSED(job)
|
||||
|
||||
return size_;
|
||||
return GenerateResolution();
|
||||
}
|
||||
|
||||
QVariant GizmoTraverser::ProcessFrameGeneration(const Node *node, const GenerateJob &job)
|
||||
{
|
||||
Q_UNUSED(node)
|
||||
Q_UNUSED(job)
|
||||
|
||||
return GenerateResolution();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,15 +34,17 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time);
|
||||
virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time) override;
|
||||
|
||||
virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job);
|
||||
virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override;
|
||||
|
||||
virtual QVector2D GenerateResolution() const
|
||||
virtual QVector2D GenerateResolution() const override
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override;
|
||||
|
||||
// FIXME: Do something about audio?
|
||||
|
||||
private:
|
||||
|
||||
@@ -274,9 +274,14 @@ void MainWindow::ToggleMaximizedPanel()
|
||||
// Find the currently focused panel
|
||||
PanelWidget* currently_hovered = PanelManager::instance()->CurrentlyHovered();
|
||||
|
||||
// If no panel is hovered, do nothing
|
||||
if (currently_hovered == nullptr) {
|
||||
return;
|
||||
// If no panel is hovered, fallback to the currently active panel
|
||||
if (!currently_hovered) {
|
||||
currently_hovered = PanelManager::instance()->CurrentlyFocused();
|
||||
|
||||
// If no panel is hovered or focused, do nothing
|
||||
if (!currently_hovered) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If this panel is not actually on the main window, this is a no-op
|
||||
|
||||
Reference in New Issue
Block a user