implemented 'ripple to' timeline actions

This commit is contained in:
itsmattkc
2019-09-24 22:45:30 +10:00
parent c33a0b50ce
commit cf3e8d80d1
17 changed files with 219 additions and 82 deletions
+7
View File
@@ -221,3 +221,10 @@ rational Block::MediaToSequenceTime(const rational &media_time)
return media_time - media_in() + in();
}
void Block::CopyParameters(Block *source, Block *dest)
{
dest->set_block_name(source->block_name());
dest->set_length(source->length());
dest->set_media_in(source->media_in());
}
+2
View File
@@ -102,6 +102,8 @@ protected:
rational MediaToSequenceTime(const rational& media_time);
static void CopyParameters(Block* source, Block* dest);
private:
NodeInput* previous_input_;
NodeOutput* block_output_;
+1 -2
View File
@@ -33,8 +33,7 @@ Block *ClipBlock::copy()
{
ClipBlock* c = new ClipBlock();
c->set_block_name(block_name());
c->set_length(length());
CopyParameters(this, c);
return c;
}
+1 -2
View File
@@ -28,8 +28,7 @@ Block *GapBlock::copy()
{
GapBlock* c = new GapBlock();
c->set_block_name(block_name());
c->set_length(length());
CopyParameters(this, c);
return c;
}
+2 -2
View File
@@ -151,7 +151,7 @@ Block *TrackOutput::NearestBlockBefore(const rational &time)
}
}
return nullptr;
return this;
}
Block *TrackOutput::NearestBlockAfter(const rational &time)
@@ -163,7 +163,7 @@ Block *TrackOutput::NearestBlockAfter(const rational &time)
}
}
return nullptr;
return this;
}
const QVector<Block *> &TrackOutput::Blocks()
+21
View File
@@ -43,6 +43,7 @@ TimelinePanel::TimelinePanel(QWidget *parent) :
connect(view_, SIGNAL(ScaleChanged(double)), this, SLOT(SetScale(double)));
connect(view_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&)));
connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), view_, SLOT(SetTime(const int64_t&)));
connect(view_, SIGNAL(TimeChanged(const int64_t&)), ruler_, SLOT(SetTime(const int64_t&)));
// FIXME: Magic number
SetScale(90.0);
@@ -98,6 +99,26 @@ void TimelinePanel::DeselectAll()
view_->DeselectAll();
}
void TimelinePanel::RippleToIn()
{
view_->RippleToIn();
}
void TimelinePanel::RippleToOut()
{
view_->RippleToOut();
}
void TimelinePanel::EditToIn()
{
view_->EditToIn();
}
void TimelinePanel::EditToOut()
{
view_->EditToOut();
}
void TimelinePanel::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
+8
View File
@@ -47,6 +47,14 @@ public:
virtual void DeselectAll() override;
virtual void RippleToIn() override;
virtual void RippleToOut() override;
virtual void EditToIn() override;
virtual void EditToOut() override;
public slots:
void SetTimebase(const rational& timebase);
-36
View File
@@ -56,42 +56,6 @@ void PanelWidget::SetBorderVisible(bool enabled)
update();
}
void PanelWidget::ZoomIn()
{
}
void PanelWidget::ZoomOut()
{
}
void PanelWidget::GoToStart()
{
}
void PanelWidget::PrevFrame()
{
}
void PanelWidget::PlayPause()
{
}
void PanelWidget::NextFrame()
{
}
void PanelWidget::GoToEnd()
{
}
void PanelWidget::SelectAll()
{
}
void PanelWidget::DeselectAll()
{
}
void PanelWidget::SetTitle(const QString &t)
{
title_ = t;
+17 -9
View File
@@ -58,7 +58,7 @@ public:
* This function is up to the Panel's interpretation of what the user intends to zoom into. Default behavior is a
* no-op.
*/
virtual void ZoomIn();
virtual void ZoomIn(){}
/**
* @brief Called whenever this panel is focused and user uses "Zoom Out" (either in menus or as a keyboard shortcut)
@@ -66,11 +66,11 @@ public:
* This function is up to the Panel's interpretation of what the user intends to zoom out of. Default behavior is a
* no-op.
*/
virtual void ZoomOut();
virtual void ZoomOut(){}
virtual void GoToStart();
virtual void GoToStart(){}
virtual void PrevFrame();
virtual void PrevFrame(){}
/**
* @brief Called whenever this panel is focused and user uses "Play/Pause" (either in menus or as a keyboard shortcut)
@@ -78,15 +78,23 @@ public:
* This function is up to the Panel's interpretation of what the user intends to zoom out of. Default behavior is a
* no-op.
*/
virtual void PlayPause();
virtual void PlayPause(){}
virtual void NextFrame();
virtual void NextFrame(){}
virtual void GoToEnd();
virtual void GoToEnd(){}
virtual void SelectAll();
virtual void SelectAll(){}
virtual void DeselectAll();
virtual void DeselectAll(){}
virtual void RippleToIn(){}
virtual void RippleToOut(){}
virtual void EditToIn(){}
virtual void EditToOut(){}
protected:
/**
+86 -7
View File
@@ -27,6 +27,7 @@
#include <QtMath>
#include <QPen>
#include "common/timecodefunctions.h"
#include "core.h"
#include "node/input/media/media.h"
#include "project/item/footage/footage.h"
@@ -217,6 +218,26 @@ void TimelineView::DeselectAll()
}
}
void TimelineView::RippleToIn()
{
RippleEditTo(olive::timeline::kTrimIn, false);
}
void TimelineView::RippleToOut()
{
RippleEditTo(olive::timeline::kTrimOut, false);
}
void TimelineView::EditToIn()
{
RippleEditTo(olive::timeline::kTrimIn, true);
}
void TimelineView::EditToOut()
{
RippleEditTo(olive::timeline::kTrimOut, true);
}
void TimelineView::SetTime(const int64_t time)
{
playhead_ = time;
@@ -228,43 +249,51 @@ void TimelineView::mousePressEvent(QMouseEvent *event)
{
active_tool_ = GetActiveTool();
if (active_tool_ != nullptr) {
if (timeline_node_ != nullptr && active_tool_ != nullptr) {
active_tool_->MousePress(event);
}
}
void TimelineView::mouseMoveEvent(QMouseEvent *event)
{
if (active_tool_ != nullptr) {
if (timeline_node_ != nullptr && active_tool_ != nullptr) {
active_tool_->MouseMove(event);
}
}
void TimelineView::mouseReleaseEvent(QMouseEvent *event)
{
if (active_tool_ != nullptr) {
if (timeline_node_ != nullptr && active_tool_ != nullptr) {
active_tool_->MouseRelease(event);
}
}
void TimelineView::dragEnterEvent(QDragEnterEvent *event)
{
import_tool_.DragEnter(event);
if (timeline_node_ != nullptr) {
import_tool_.DragEnter(event);
}
}
void TimelineView::dragMoveEvent(QDragMoveEvent *event)
{
import_tool_.DragMove(event);
if (timeline_node_ != nullptr) {
import_tool_.DragMove(event);
}
}
void TimelineView::dragLeaveEvent(QDragLeaveEvent *event)
{
import_tool_.DragLeave(event);
if (timeline_node_ != nullptr) {
import_tool_.DragLeave(event);
}
}
void TimelineView::dropEvent(QDropEvent *event)
{
import_tool_.DragDrop(event);
if (timeline_node_ != nullptr) {
import_tool_.DragDrop(event);
}
}
void TimelineView::resizeEvent(QResizeEvent *event)
@@ -372,6 +401,56 @@ void TimelineView::ClearGhosts()
}
}
void TimelineView::RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps)
{
rational playhead_time = olive::timestamp_to_time(playhead_, timebase_);
rational closest_point_to_playhead;
if (mode == olive::timeline::kTrimIn) {
closest_point_to_playhead = 0;
} else {
closest_point_to_playhead = RATIONAL_MAX;
}
foreach (TrackOutput* track, timeline_node_->Tracks()) {
Block* b = track->NearestBlockBefore(playhead_time);
if (b != nullptr) {
if (mode == olive::timeline::kTrimIn) {
closest_point_to_playhead = qMax(b->in(), closest_point_to_playhead);
} else {
closest_point_to_playhead = qMin(b->out(), closest_point_to_playhead);
}
}
}
QUndoCommand* command = new QUndoCommand();
if (closest_point_to_playhead == playhead_time) {
// Remove one frame only
if (mode == olive::timeline::kTrimIn) {
playhead_time += timebase_;
} else {
playhead_time -= timebase_;
}
}
foreach (TrackOutput* track, timeline_node_->Tracks()) {
new TrackRippleRemoveAreaCommand(track,
qMin(closest_point_to_playhead, playhead_time),
qMax(closest_point_to_playhead, playhead_time),
command);
}
olive::undo_stack.pushIfHasChildren(command);
if (mode == olive::timeline::kTrimIn && !insert_gaps) {
int64_t new_time = olive::time_to_timestamp(closest_point_to_playhead, timebase_);
SetTime(new_time);
emit TimeChanged(new_time);
}
}
void TimelineView::BlockChanged()
{
TimelineViewRect* rect = block_items_[static_cast<Block*>(sender())];
+12
View File
@@ -56,6 +56,14 @@ public:
void DeselectAll();
void RippleToIn();
void RippleToOut();
void EditToIn();
void EditToOut();
public slots:
void SetTimebase(const rational& timebase);
@@ -76,6 +84,8 @@ signals:
void TimebaseChanged(const rational& timebase);
void TimeChanged(const int64_t& time);
protected:
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
@@ -346,6 +356,8 @@ private:
void ClearGhosts();
void RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps);
QGraphicsScene scene_;
double scale_;
+17 -16
View File
@@ -29,7 +29,6 @@ Block* CreateSplitBlock(Block* block, rational point, QObject* parent = nullptr)
copy->set_length_and_media_in(block->length() - (point - block->in()));
copy->setParent(parent);
return copy;
}
@@ -142,7 +141,8 @@ TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(TrackOutput *track, r
out_(out),
splice_(nullptr),
trim_out_(nullptr),
trim_in_(nullptr)
trim_in_(nullptr),
insert_(nullptr)
{
}
@@ -168,40 +168,39 @@ void TrackRippleRemoveAreaCommand::redo()
}
}
track_->BlockInvalidateCache();
// If we picked up a block to splice
if (splice_ != nullptr) {
// Split the block here
Block* copy = CreateSplitBlock(splice_, in_);
Block* copy = CreateSplitBlock(splice_, out_);
splice_original_length_ = splice_->length();
splice_->set_length(out_ - splice_->in());
track_->AddBlockToGraph(copy);
Node::CopyInputs(splice_, copy);
track_->InsertBlockAfter(copy, splice_);
// Perform all further actions as if we were just trimming these clips
trim_out_ = splice_;
trim_in_ = copy;
}
// If we picked up a block to trim the in point of
if (trim_in_ != nullptr && trim_in_->in() < out_) {
if (trim_in_ != nullptr) {
trim_in_old_length_ = trim_in_->length();
trim_in_new_length_ = trim_in_->out() - out_;
}
// If we picked up a block to trim the out point of
if (trim_out_ != nullptr && trim_out_->out() > in_) {
if (trim_out_ != nullptr) {
trim_out_old_length_ = trim_out_->length();
trim_out_new_length_ = in_ - trim_out_->in();
}
track_->BlockInvalidateCache();
// If we're splicing, trim_in_ is a copy
if (splice_ != nullptr) {
track_->AddBlockToGraph(trim_in_);
Node::CopyInputs(splice_, trim_in_);
track_->InsertBlockAfter(trim_in_, splice_);
}
// If we picked up a block to trim the in point of
if (trim_in_old_length_ != trim_in_new_length_) {
trim_in_->set_length_and_media_in(trim_in_new_length_);
@@ -272,6 +271,8 @@ void TrackRippleRemoveAreaCommand::undo()
// Remove node
TakeNodeFromParentGraph(trim_in_, &memory_manager_);
splice_->set_length(splice_original_length_);
}
track_->UnblockInvalidateCache();
+1
View File
@@ -131,6 +131,7 @@ protected:
rational out_;
Block* splice_;
rational splice_original_length_;
Block* trim_out_;
QVector<Block*> removed_blocks_;
+9 -2
View File
@@ -28,13 +28,15 @@
#include "common/timecodefunctions.h"
#include "common/qtversionabstraction.h"
#include "config/config.h"
#include "core.h"
TimeRuler::TimeRuler(bool text_visible, QWidget* parent) :
QWidget(parent),
scroll_(0),
centered_text_(true),
scale_(1.0), // FIXME: Temporary value
time_(0)
scale_(1.0),
time_(0),
snapping_(false)
{
QFontMetrics fm = fontMetrics();
@@ -92,6 +94,11 @@ void TimeRuler::SetTimebase(const rational &r)
update();
}
void TimeRuler::SetSnapping(bool snapping)
{
snapping_ = snapping;
}
const int64_t &TimeRuler::GetTime()
{
return time_;
+4
View File
@@ -42,6 +42,8 @@ public:
void SetCenteredText(bool c);
void SetSnapping(bool snapping);
const int64_t& GetTime();
public slots:
@@ -94,6 +96,8 @@ private:
TimelinePlayhead style_;
bool snapping_;
};
#endif // TIMERULER_H
+26 -6
View File
@@ -55,10 +55,10 @@ MainMenu::MainMenu(QMainWindow *parent) :
//
edit_menu_ = new Menu(this);
edit_undo_item_ = olive::undo_stack.createUndoAction(this); //edit_menu_->AddItem("undo", nullptr, nullptr, "Ctrl+Z");
edit_undo_item_ = olive::undo_stack.createUndoAction(this);
Menu::ConformItem(edit_undo_item_, "undo", nullptr, nullptr, "Ctrl+Z");
edit_menu_->addAction(edit_undo_item_);
edit_redo_item_ = olive::undo_stack.createRedoAction(this); //edit_menu_->AddItem("redo", nullptr, nullptr, "Ctrl+Shift+Z");
edit_redo_item_ = olive::undo_stack.createRedoAction(this);
Menu::ConformItem(edit_redo_item_, "redo", nullptr, nullptr, "Ctrl+Shift+Z");
edit_menu_->addAction(edit_redo_item_);
@@ -70,10 +70,10 @@ MainMenu::MainMenu(QMainWindow *parent) :
edit_menu_->addSeparator();
olive::menu_shared.AddItemsForClipEditMenu(edit_menu_);
edit_menu_->addSeparator();
edit_ripple_to_in_item_ = edit_menu_->AddItem("rippletoin", nullptr, nullptr, "Q");
edit_ripple_to_out_item_ = edit_menu_->AddItem("rippletoout", nullptr, nullptr, "W");
edit_edit_to_in_item_ = edit_menu_->AddItem("edittoin", nullptr, nullptr, "Ctrl+Alt+Q");
edit_edit_to_out_item_ = edit_menu_->AddItem("edittoout", nullptr, nullptr, "Ctrl+Alt+W");
edit_ripple_to_in_item_ = edit_menu_->AddItem("rippletoin", this, SLOT(RippleToInTriggered()), "Q");
edit_ripple_to_out_item_ = edit_menu_->AddItem("rippletoout", this, SLOT(RippleToOutTriggered()), "W");
edit_edit_to_in_item_ = edit_menu_->AddItem("edittoin", this, SLOT(EditToInTriggered()), "Ctrl+Alt+Q");
edit_edit_to_out_item_ = edit_menu_->AddItem("edittoout", this, SLOT(EditToOutTriggered()), "Ctrl+Alt+W");
edit_menu_->addSeparator();
olive::menu_shared.AddItemsForInOutMenu(edit_menu_);
edit_delete_inout_item_ = edit_menu_->AddItem("deleteinout", nullptr, nullptr, ";");
@@ -407,6 +407,26 @@ void MainMenu::DeselectAllTriggered()
olive::panel_manager->CurrentlyFocused()->DeselectAll();
}
void MainMenu::RippleToInTriggered()
{
olive::panel_manager->CurrentlyFocused()->RippleToIn();
}
void MainMenu::RippleToOutTriggered()
{
olive::panel_manager->CurrentlyFocused()->RippleToOut();
}
void MainMenu::EditToInTriggered()
{
olive::panel_manager->CurrentlyFocused()->EditToIn();
}
void MainMenu::EditToOutTriggered()
{
olive::panel_manager->CurrentlyFocused()->EditToOut();
}
void MainMenu::Retranslate()
{
// MenuShared is not a QWidget and therefore does not receive a LanguageEvent, we use MainMenu's to update it
+5
View File
@@ -101,6 +101,11 @@ private slots:
void SelectAllTriggered();
void DeselectAllTriggered();
void RippleToInTriggered();
void RippleToOutTriggered();
void EditToInTriggered();
void EditToOutTriggered();
private:
/**
* @brief Set strings based on the current application language.