timeline: implemented nudging #1692

This commit is contained in:
itsmattkc
2021-07-30 19:17:26 -07:00
parent 01d435d80d
commit 930d8309d3
14 changed files with 195 additions and 37 deletions
+7
View File
@@ -202,6 +202,13 @@ void TimeRangeList::remove(const TimeRange &remove)
util_remove(&array_, remove);
}
void TimeRangeList::remove(const TimeRangeList &list)
{
for (const TimeRange &r : list) {
remove(r);
}
}
bool TimeRangeList::contains(const TimeRange &range, bool in_inclusive, bool out_inclusive) const
{
for (int i=0;i<size();i++) {
+11
View File
@@ -80,6 +80,7 @@ public:
void insert(TimeRange range_to_add);
void remove(const TimeRange& remove);
void remove(const TimeRangeList &list);
template <typename T>
static void util_remove(QVector<T> *list, const TimeRange &remove)
@@ -148,6 +149,16 @@ public:
return array_.constEnd();
}
const_iterator cbegin() const
{
return begin();
}
const_iterator cend() const
{
return end();
}
const TimeRange& first() const
{
return array_.first();
+34 -24
View File
@@ -38,67 +38,67 @@ TimelinePanel::TimelinePanel(QWidget *parent) :
void TimelinePanel::SplitAtPlayhead()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->SplitAtPlayhead();
timeline_widget()->SplitAtPlayhead();
}
QByteArray TimelinePanel::SaveSplitterState() const
{
return static_cast<TimelineWidget*>(GetTimeBasedWidget())->SaveSplitterState();
return timeline_widget()->SaveSplitterState();
}
void TimelinePanel::RestoreSplitterState(const QByteArray &state)
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->RestoreSplitterState(state);
timeline_widget()->RestoreSplitterState(state);
}
void TimelinePanel::SelectAll()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->SelectAll();
timeline_widget()->SelectAll();
}
void TimelinePanel::DeselectAll()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeselectAll();
timeline_widget()->DeselectAll();
}
void TimelinePanel::RippleToIn()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->RippleToIn();
timeline_widget()->RippleToIn();
}
void TimelinePanel::RippleToOut()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->RippleToOut();
timeline_widget()->RippleToOut();
}
void TimelinePanel::EditToIn()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->EditToIn();
timeline_widget()->EditToIn();
}
void TimelinePanel::EditToOut()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->EditToOut();
timeline_widget()->EditToOut();
}
void TimelinePanel::DeleteSelected()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteSelected(false);
timeline_widget()->DeleteSelected(false);
}
void TimelinePanel::RippleDelete()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteSelected(true);
timeline_widget()->DeleteSelected(true);
}
void TimelinePanel::IncreaseTrackHeight()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->IncreaseTrackHeight();
timeline_widget()->IncreaseTrackHeight();
}
void TimelinePanel::DecreaseTrackHeight()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DecreaseTrackHeight();
timeline_widget()->DecreaseTrackHeight();
}
void TimelinePanel::Insert()
@@ -121,57 +121,67 @@ void TimelinePanel::Overwrite()
void TimelinePanel::ToggleLinks()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->ToggleLinksOnSelected();
timeline_widget()->ToggleLinksOnSelected();
}
void TimelinePanel::CutSelected()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->CopySelected(true);
timeline_widget()->CopySelected(true);
}
void TimelinePanel::CopySelected()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->CopySelected(false);
timeline_widget()->CopySelected(false);
}
void TimelinePanel::Paste()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->Paste(false);
timeline_widget()->Paste(false);
}
void TimelinePanel::PasteInsert()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->Paste(true);
timeline_widget()->Paste(true);
}
void TimelinePanel::DeleteInToOut()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteInToOut(false);
timeline_widget()->DeleteInToOut(false);
}
void TimelinePanel::RippleDeleteInToOut()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteInToOut(true);
timeline_widget()->DeleteInToOut(true);
}
void TimelinePanel::ToggleSelectedEnabled()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->ToggleSelectedEnabled();
timeline_widget()->ToggleSelectedEnabled();
}
void TimelinePanel::SetColorLabel(int index)
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->SetColorLabel(index);
timeline_widget()->SetColorLabel(index);
}
void TimelinePanel::NudgeLeft()
{
timeline_widget()->NudgeLeft();
}
void TimelinePanel::NudgeRight()
{
timeline_widget()->NudgeRight();
}
void TimelinePanel::InsertFootageAtPlayhead(const QVector<ViewerOutput *> &footage)
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->InsertFootageAtPlayhead(footage);
timeline_widget()->InsertFootageAtPlayhead(footage);
}
void TimelinePanel::OverwriteFootageAtPlayhead(const QVector<ViewerOutput *> &footage)
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->OverwriteFootageAtPlayhead(footage);
timeline_widget()->OverwriteFootageAtPlayhead(footage);
}
void TimelinePanel::Retranslate()
+9
View File
@@ -35,6 +35,11 @@ class TimelinePanel : public TimeBasedPanel
public:
TimelinePanel(QWidget* parent);
inline TimelineWidget *timeline_widget() const
{
return static_cast<TimelineWidget*>(GetTimeBasedWidget());
}
void SplitAtPlayhead();
QByteArray SaveSplitterState() const;
@@ -83,6 +88,10 @@ public:
virtual void SetColorLabel(int index) override;
virtual void NudgeLeft() override;
virtual void NudgeRight() override;
void InsertFootageAtPlayhead(const QVector<ViewerOutput *> &footage);
void OverwriteFootageAtPlayhead(const QVector<ViewerOutput *> &footage);
+4
View File
@@ -170,6 +170,10 @@ public:
virtual void SetColorLabel(int){}
virtual void NudgeLeft(){}
virtual void NudgeRight(){}
signals:
void CloseRequested();
+64 -3
View File
@@ -504,7 +504,7 @@ void TimelineWidget::DeleteSelected(bool ripple)
ReplaceBlocksWithGaps(clips_to_delete, true, command);
// Remove all selections
command->add_child(new SetSelectionsCommand(this, TimelineWidgetSelections(), GetSelections()));
command->add_child(new SetSelectionsCommand(this, TimelineWidgetSelections(), GetSelections(), false));
// Insert ripple command now that it's all cleaned up gaps
if (ripple) {
@@ -724,6 +724,20 @@ void TimelineWidget::SetColorLabel(int index)
}
}
void TimelineWidget::NudgeLeft()
{
if (GetConnectedNode()) {
NudgeInternal(-timebase());
}
}
void TimelineWidget::NudgeRight()
{
if (GetConnectedNode()) {
NudgeInternal(timebase());
}
}
void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, MultiUndoCommand *command)
{
for (int i=0;i<Track::kCount;i++) {
@@ -1145,6 +1159,23 @@ void TimelineWidget::UpdateViewTimebases()
}
}
void TimelineWidget::NudgeInternal(const rational &amount)
{
MultiUndoCommand *command = new MultiUndoCommand();
foreach (Block* b, selected_blocks_) {
command->add_child(new TrackReplaceBlockWithGapCommand(b->track(), b, false));
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(b->track()->type()), b->track()->Index(), b, b->in() + amount));
}
// Nudge selections
TimelineWidgetSelections new_sel = GetSelections();
new_sel.ShiftTime(amount);
command->add_child(new TimelineWidget::SetSelectionsCommand(this, new_sel, GetSelections(), true));
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void TimelineWidget::SetViewBeamCursor(const TimelineCoordinate &coord)
{
foreach (TimelineAndTrackView* tview, views_) {
@@ -1428,6 +1459,31 @@ QVector<Block *> TimelineWidget::GetBlocksInGlobalRect(const QPoint &p1, const Q
return blocks_in_rect;
}
QVector<Block *> TimelineWidget::GetBlocksInSelection(const TimelineWidgetSelections &sel)
{
QVector<Block *> blocks;
for (auto it=sel.cbegin(); it!=sel.cend(); it++) {
const Track::Reference &ref = it.key();
const TimeRangeList &list = it.value();
for (const TimeRange &r : list) {
Track *track = GetTrackFromReference(ref);
if (track) {
for (Block *b : track->Blocks()) {
if (r.Contains(b->range())) {
blocks.append(b);
} else if (b->in() >= r.out()) {
break;
}
}
}
}
}
return blocks;
}
void TimelineWidget::HideSnaps()
{
foreach (TimelineAndTrackView* tview, views_) {
@@ -1474,7 +1530,7 @@ void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_lin
QVector<Block*> items_in_rubberband = GetBlocksInGlobalRect(drag_origin_, rubberband_now);
// Reset selection to whatever it was before
SetSelections(rubberband_old_selections_);
SetSelections(rubberband_old_selections_, false);
// Add any blocks in rubberband
rubberband_now_selected_.clear();
@@ -1544,8 +1600,13 @@ void TimelineWidget::RemoveSelection(Block *item)
}
}
void TimelineWidget::SetSelections(const TimelineWidgetSelections &s)
void TimelineWidget::SetSelections(const TimelineWidgetSelections &s, bool process_block_changes)
{
if (process_block_changes) {
SignalDeselectedBlocks(GetBlocksInSelection(selections_.Subtracted(s)));
SignalSelectedBlocks(GetBlocksInSelection(s.Subtracted(selections_)));
}
selections_ = s;
UpdateViewports();
+15 -5
View File
@@ -91,6 +91,10 @@ public:
void SetColorLabel(int index);
void NudgeLeft();
void NudgeRight();
/**
* @brief Timelines should always be connected to sequences
*/
@@ -133,7 +137,7 @@ public:
return selections_;
}
void SetSelections(const TimelineWidgetSelections &s);
void SetSelections(const TimelineWidgetSelections &s, bool process_block_changes);
Track* GetTrackFromReference(const Track::Reference& ref) const;
@@ -208,10 +212,11 @@ public:
class SetSelectionsCommand : public UndoCommand {
public:
SetSelectionsCommand(TimelineWidget* timeline, const TimelineWidgetSelections& now, const TimelineWidgetSelections& old) :
SetSelectionsCommand(TimelineWidget* timeline, const TimelineWidgetSelections& now, const TimelineWidgetSelections& old, bool process_block_changes) :
timeline_(timeline),
old_(old),
now_(now)
now_(now),
process_block_changes_(process_block_changes)
{
}
@@ -220,18 +225,19 @@ public:
protected:
virtual void redo() override
{
timeline_->SetSelections(now_);
timeline_->SetSelections(now_, process_block_changes_);
}
virtual void undo() override
{
timeline_->SetSelections(old_);
timeline_->SetSelections(old_, process_block_changes_);
}
private:
TimelineWidget* timeline_;
TimelineWidgetSelections old_;
TimelineWidgetSelections now_;
bool process_block_changes_;
};
@@ -271,6 +277,8 @@ private:
QVector<Block*> GetBlocksInGlobalRect(const QPoint &p1, const QPoint &p2);
QVector<Block*> GetBlocksInSelection(const TimelineWidgetSelections &sel);
QPoint drag_origin_;
QRubberBand rubberband_;
@@ -307,6 +315,8 @@ private:
void UpdateViewTimebases();
void NudgeInternal(const rational &amount);
private slots:
void ViewMousePressed(TimelineViewMouseEvent* event);
void ViewMouseMoved(TimelineViewMouseEvent* event);
@@ -68,4 +68,17 @@ void TimelineWidgetSelections::TrimOut(const rational &diff)
}
}
void TimelineWidgetSelections::Subtract(const TimelineWidgetSelections &selections)
{
for (auto it=selections.cbegin(); it!=selections.cend(); it++) {
const Track::Reference &track = it.key();
const TimeRangeList &their_list = it.value();
if (this->contains(track)) {
TimeRangeList &our_list = (*this)[it.key()];
our_list.remove(their_list);
}
}
}
}
@@ -41,6 +41,15 @@ public:
void TrimOut(const rational& diff);
void Subtract(const TimelineWidgetSelections &selections);
TimelineWidgetSelections Subtracted(const TimelineWidgetSelections &selections) const
{
TimelineWidgetSelections copy = *this;
copy.Subtract(selections);
return copy;
}
};
}
+5 -1
View File
@@ -48,7 +48,7 @@ void EditTool::MouseMove(TimelineViewMouseEvent *event)
}
}
parent()->SetSelections(start_selections_);
parent()->SetSelections(start_selections_, false);
parent()->AddSelection(TimeRange(start_coord_.GetFrame(), end_frame),
start_coord_.GetTrack());
} else {
@@ -73,6 +73,10 @@ void EditTool::MouseMove(TimelineViewMouseEvent *event)
void EditTool::MouseRelease(TimelineViewMouseEvent *event)
{
auto current_sel = parent()->GetSelections();
parent()->SetSelections(start_selections_, false);
parent()->SetSelections(current_sel, true);
dragging_ = false;
}
+3 -3
View File
@@ -574,7 +574,7 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
} else {
new_sel.TrimOut(reference_ghost->GetOutAdjustment());
}
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections()));
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections(), false));
}
}
@@ -620,7 +620,7 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
TimelineWidgetSelections new_sel = parent()->GetSelections();
new_sel.ShiftTime(blocks_moving.first().ghost->GetInAdjustment());
new_sel.ShiftTracks(drag_track_type_, blocks_moving.first().ghost->GetTrackAdjustment());
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections()));
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections(), false));
}
if (!blocks_sliding.isEmpty()) {
@@ -681,7 +681,7 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
// Adjust selections
TimelineWidgetSelections new_sel = parent()->GetSelections();
new_sel.ShiftTime(movement);
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections()));
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections(), false));
}
}
+1 -1
View File
@@ -160,7 +160,7 @@ void RippleTool::FinishDrag(TimelineViewMouseEvent *event)
} else {
new_sel.TrimOut(reference_ghost->GetOutAdjustment());
}
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections()));
command->add_child(new TimelineWidget::SetSelectionsCommand(parent(), new_sel, parent()->GetSelections(), false));
Core::instance()->undo_stack()->push(command);
} else {
+15
View File
@@ -108,6 +108,9 @@ MainMenu::MainMenu(MainWindow *parent) :
edit_edit_to_in_item_ = edit_menu_->AddItem("edittoin", this, &MainMenu::EditToInTriggered, "Ctrl+Alt+Q");
edit_edit_to_out_item_ = edit_menu_->AddItem("edittoout", this, &MainMenu::EditToOutTriggered, "Ctrl+Alt+W");
edit_menu_->addSeparator();
edit_nudge_left_item_ = edit_menu_->AddItem("nudgeleft", this, &MainMenu::NudgeLeftTriggered, "Alt+Left");
edit_nudge_right_item_ = edit_menu_->AddItem("nudgeright", this, &MainMenu::NudgeRightTriggered, "Alt+Right");
edit_menu_->addSeparator();
MenuShared::instance()->AddItemsForInOutMenu(edit_menu_);
edit_delete_inout_item_ = edit_menu_->AddItem("deleteinout", this, &MainMenu::DeleteInOutTriggered, ";");
edit_ripple_delete_inout_item_ = edit_menu_->AddItem("rippledeleteinout", this, &MainMenu::RippleDeleteInOutTriggered, "'");
@@ -537,6 +540,16 @@ void MainMenu::EditToOutTriggered()
PanelManager::instance()->CurrentlyFocused()->EditToOut();
}
void MainMenu::NudgeLeftTriggered()
{
PanelManager::instance()->CurrentlyFocused()->NudgeLeft();
}
void MainMenu::NudgeRightTriggered()
{
PanelManager::instance()->CurrentlyFocused()->NudgeRight();
}
void MainMenu::ActionSearchTriggered()
{
ActionSearch as(parentWidget());
@@ -662,6 +675,8 @@ void MainMenu::Retranslate()
edit_ripple_to_out_item_->setText(tr("Ripple to Out Point"));
edit_edit_to_in_item_->setText(tr("Edit to In Point"));
edit_edit_to_out_item_->setText(tr("Edit to Out Point"));
edit_nudge_left_item_->setText(tr("Nudge Left"));
edit_nudge_right_item_->setText(tr("Nudge Right"));
edit_delete_inout_item_->setText(tr("Delete In/Out Point"));
edit_ripple_delete_inout_item_->setText(tr("Ripple Delete In/Out Point"));
edit_set_marker_item_->setText(tr("Set/Edit Marker"));
+5
View File
@@ -154,6 +154,9 @@ private slots:
void EditToInTriggered();
void EditToOutTriggered();
void NudgeLeftTriggered();
void NudgeRightTriggered();
void ActionSearchTriggered();
void ShuttleLeftTriggered();
@@ -218,6 +221,8 @@ private:
QAction* edit_ripple_to_out_item_;
QAction* edit_edit_to_in_item_;
QAction* edit_edit_to_out_item_;
QAction* edit_nudge_left_item_;
QAction* edit_nudge_right_item_;
QAction* edit_delete_inout_item_;
QAction* edit_ripple_delete_inout_item_;
QAction* edit_set_marker_item_;