implemented 'ripple to' timeline actions
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
/**
|
||||
|
||||
@@ -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())];
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -131,6 +131,7 @@ protected:
|
||||
rational out_;
|
||||
|
||||
Block* splice_;
|
||||
rational splice_original_length_;
|
||||
|
||||
Block* trim_out_;
|
||||
QVector<Block*> removed_blocks_;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user