From 30be1b626d4da573ba0c2ed8bb947eb65ef38aa4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 19 Sep 2019 17:05:41 +1000 Subject: [PATCH] further ripple progress --- app/common/timelinecommon.h | 20 + app/node/output/timeline/timeline.cpp | 66 ++++ app/node/output/timeline/timeline.h | 4 + app/node/output/track/track.cpp | 12 + app/node/output/track/track.h | 2 + app/widget/timelineview/timelineview.h | 10 + .../timelineview/timelineviewghostitem.cpp | 6 +- .../timelineview/timelineviewghostitem.h | 14 +- app/widget/timelineview/tool/import.cpp | 2 +- app/widget/timelineview/tool/pointer.cpp | 345 +++++++++--------- app/widget/timelineview/tool/ripple.cpp | 20 +- app/widget/timelineview/tool/tool.cpp | 8 +- 12 files changed, 317 insertions(+), 192 deletions(-) create mode 100644 app/common/timelinecommon.h diff --git a/app/common/timelinecommon.h b/app/common/timelinecommon.h new file mode 100644 index 000000000..01cce97d3 --- /dev/null +++ b/app/common/timelinecommon.h @@ -0,0 +1,20 @@ +#ifndef TIMELINECOMMON_H +#define TIMELINECOMMON_H + +namespace olive { + +namespace timeline { + +enum MovementMode { + kNone, + kMove, + kTrimIn, + kTrimOut +}; + +} + +} + + +#endif // TIMELINECOMMON_H diff --git a/app/node/output/timeline/timeline.cpp b/app/node/output/timeline/timeline.cpp index 0b73535c9..12aff1885 100644 --- a/app/node/output/timeline/timeline.cpp +++ b/app/node/output/timeline/timeline.cpp @@ -70,6 +70,7 @@ void TimelineOutput::AttachTimeline(TimelinePanel *timeline) disconnect(view, SIGNAL(RequestPlaceBlock(Block*, rational, int)), this, SLOT(PlaceBlock(Block*, rational, int))); disconnect(view, SIGNAL(RequestReplaceBlock(Block*, Block*, int)), this, SLOT(ReplaceBlock(Block*, Block*, int))); disconnect(view, SIGNAL(RequestSplitAtTime(rational, int)), this, SLOT(SplitAtTime(rational, int))); + disconnect(view, SIGNAL(RequestRippleBlocks(QList, rational, olive::timeline::MovementMode)), this, SLOT(RippleBlocks(QList, rational, olive::timeline::MovementMode))); // Remove existing UI objects from TimelinePanel attached_timeline_->Clear(); @@ -93,6 +94,7 @@ void TimelineOutput::AttachTimeline(TimelinePanel *timeline) connect(view, SIGNAL(RequestPlaceBlock(Block*, rational, int)), this, SLOT(PlaceBlock(Block*, rational, int))); connect(view, SIGNAL(RequestReplaceBlock(Block*, Block*, int)), this, SLOT(ReplaceBlock(Block*, Block*, int))); connect(view, SIGNAL(RequestSplitAtTime(rational, int)), this, SLOT(SplitAtTime(rational, int))); + connect(view, SIGNAL(RequestRippleBlocks(QList, rational, olive::timeline::MovementMode)), this, SLOT(RippleBlocks(QList, rational, olive::timeline::MovementMode))); } } @@ -219,6 +221,20 @@ void TimelineOutput::AddTrack() } } +TrackOutput *TimelineOutput::TrackFromBlock(Block *block) +{ + Block* n = block; + + // Find last valid block in Sequence and assume its a track + while (n->next() != nullptr) { + n = n->next(); + } + + // Downside of this approach is the usage of dynamic_cast, alternative would be looping through all known tracks and + // seeing if the contain the Block, but this seems slower + return dynamic_cast(n); +} + void TimelineOutput::TrackConnectionAdded(NodeEdgePtr edge) { if (edge->input() != track_input()) { @@ -314,3 +330,53 @@ void TimelineOutput::ResizeBlock(Block *block, rational new_length) { block->set_length(new_length); } + +void TimelineOutput::RippleBlocks(QList blocks, rational ripple_length, olive::timeline::MovementMode mode) +{ + if (blocks.isEmpty() + || ripple_length == 0 + || (mode != olive::timeline::kTrimIn && mode != olive::timeline::kTrimOut)) { + return; + } + + if (mode == olive::timeline::kTrimIn) { + // Flip the ripple length if we're trimming the in point + ripple_length = -ripple_length; + } + + QVector rippled_tracks; + + rational ripple_point = RATIONAL_MAX; + + // Ripple each Block as requested + foreach (Block* b, blocks) { + if (mode == olive::timeline::kTrimIn) { + ripple_point = qMin(ripple_point, b->in()); + + // Extend media in point + b->set_media_in(b->media_in() - ripple_length); + } else { + ripple_point = qMin(ripple_point, b->out()); + } + + b->set_length(b->length() + ripple_length); + + rippled_tracks.append(TrackFromBlock(b)); + } + + // For each track that did not have a rippled clip, insert a Gap to keep all tracks synchronized + // FIXME: Assumes rippling out point further out + foreach (TrackOutput* track, track_cache_) { + + if (!rippled_tracks.contains(track)) { + Block* block_after_time = track->NearestBlockAfter(ripple_point); + + if (block_after_time != nullptr) { + // Insert Gap block before this Block + GapBlock* gap = new GapBlock(); + gap->set_length(ripple_length); + track->InsertBlockBefore(gap, block_after_time); + } + } + } +} diff --git a/app/node/output/timeline/timeline.h b/app/node/output/timeline/timeline.h index c2fc80f60..d9685eb4a 100644 --- a/app/node/output/timeline/timeline.h +++ b/app/node/output/timeline/timeline.h @@ -63,6 +63,8 @@ private: void AddTrack(); + static TrackOutput* TrackFromBlock(Block* block); + TimelinePanel* attached_timeline_; NodeInput* track_input_; @@ -130,6 +132,8 @@ private slots: */ void ResizeBlock(Block* block, rational new_length); + void RippleBlocks(QList blocks, rational ripple_length, olive::timeline::MovementMode mode); + }; #endif // TIMELINEOUTPUT_H diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index bf5adfe43..51c8c2e42 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -151,6 +151,18 @@ NodeOutput* TrackOutput::track_output() return track_output_; } +Block *TrackOutput::NearestBlockAfter(const rational &time) +{ + foreach (Block* block, block_cache_) { + // Blocks are sorted by time, so the first Block after this time is the correct Block + if (block->in() >= time) { + return block; + } + } + + return nullptr; +} + void TrackOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from) { // We intercept IC signals from Blocks since we may be performing several options and they may over-signal diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 0b4b9137c..1a22cd72e 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -61,6 +61,8 @@ public: NodeOutput* track_output(); + Block* NearestBlockAfter(const rational& time); + virtual void InvalidateCache(const rational& start_range, const rational& end_range, NodeInput* from = nullptr) override; /** diff --git a/app/widget/timelineview/timelineview.h b/app/widget/timelineview/timelineview.h index 0fbae0830..b1bb6f74c 100644 --- a/app/widget/timelineview/timelineview.h +++ b/app/widget/timelineview/timelineview.h @@ -62,6 +62,7 @@ signals: void RequestPlaceBlock(Block* block, rational start, int track); void RequestReplaceBlock(Block* old, Block* replace, int track); void RequestSplitAtTime(rational time, int track); + void RequestRippleBlocks(QList blocks, rational length, olive::timeline::MovementMode mode); void UserSetScale(double scale); @@ -179,6 +180,15 @@ private: virtual void MouseReleaseInternal(QMouseEvent *event); virtual rational FrameValidateInternal(rational time_movement, QVector); private: + void InitiateDrag(const QPoint &mouse_pos); + void ProcessDrag(const QPoint &mouse_pos); + + QList GetSelectedClips(); + + bool IsClipTrimmable(TimelineViewClipItem* clip, + const QList& items, + const olive::timeline::MovementMode& mode); + int track_start_; bool movement_allowed_; }; diff --git a/app/widget/timelineview/timelineviewghostitem.cpp b/app/widget/timelineview/timelineviewghostitem.cpp index 48a8668f4..c8d7e92a4 100644 --- a/app/widget/timelineview/timelineviewghostitem.cpp +++ b/app/widget/timelineview/timelineviewghostitem.cpp @@ -28,7 +28,7 @@ TimelineViewGhostItem::TimelineViewGhostItem(QGraphicsItem *parent) : out_adj_(0), track_adj_(0), stream_(nullptr), - mode_(kNone) + mode_(olive::timeline::kNone) { setBrush(Qt::NoBrush); setPen(QPen(Qt::yellow, 2)); // FIXME: Make customizable via CSS @@ -135,12 +135,12 @@ int TimelineViewGhostItem::GetAdjustedTrack() const return track_ + track_adj_; } -const TimelineViewGhostItem::Mode &TimelineViewGhostItem::mode() const +const olive::timeline::MovementMode &TimelineViewGhostItem::mode() const { return mode_; } -void TimelineViewGhostItem::SetMode(const TimelineViewGhostItem::Mode &mode) +void TimelineViewGhostItem::SetMode(const olive::timeline::MovementMode &mode) { mode_ = mode; } diff --git a/app/widget/timelineview/timelineviewghostitem.h b/app/widget/timelineview/timelineviewghostitem.h index 43109b7d9..5bb62932b 100644 --- a/app/widget/timelineview/timelineviewghostitem.h +++ b/app/widget/timelineview/timelineviewghostitem.h @@ -23,6 +23,7 @@ #include +#include "common/timelinecommon.h" #include "project/item/footage/footage.h" #include "timelineviewclipitem.h" #include "timelineviewrect.h" @@ -33,12 +34,7 @@ class TimelineViewGhostItem : public TimelineViewRect { public: - enum Mode { - kNone, - kMove, - kTrimIn, - kTrimOut - }; + TimelineViewGhostItem(QGraphicsItem* parent = nullptr); @@ -65,8 +61,8 @@ public: rational GetAdjustedOut() const; int GetAdjustedTrack() const; - const Mode& mode() const; - void SetMode(const Mode& mode); + const olive::timeline::MovementMode& mode() const; + void SetMode(const olive::timeline::MovementMode& mode); virtual void UpdateRect() override; @@ -83,7 +79,7 @@ private: StreamPtr stream_; - Mode mode_; + olive::timeline::MovementMode mode_; }; #endif // TIMELINEVIEWGHOSTITEM_H diff --git a/app/widget/timelineview/tool/import.cpp b/app/widget/timelineview/tool/import.cpp index 49e38a87d..a4435b07b 100644 --- a/app/widget/timelineview/tool/import.cpp +++ b/app/widget/timelineview/tool/import.cpp @@ -96,7 +96,7 @@ void TimelineView::ImportTool::DragEnter(QDragEnterEvent *event) snap_points_.append(ghost->Out()); ghost->setData(0, QVariant::fromValue(stream)); - ghost->SetMode(TimelineViewGhostItem::kMove); + ghost->SetMode(olive::timeline::kMove); parent()->AddGhost(ghost); diff --git a/app/widget/timelineview/tool/pointer.cpp b/app/widget/timelineview/tool/pointer.cpp index 3ef576cf0..9ef86ad72 100644 --- a/app/widget/timelineview/tool/pointer.cpp +++ b/app/widget/timelineview/tool/pointer.cpp @@ -67,126 +67,7 @@ void TimelineView::PointerTool::MouseMove(QMouseEvent *event) if (!dragging_) { // If we haven't started dragging yet, we'll initiate a drag here - - // Record where the drag started in timeline coordinates - drag_start_ = GetScenePos(event->pos()); - - // Get the item that was clicked - TimelineViewRect* clicked_item = dynamic_cast(GetItemAtScenePos(drag_start_)); - - // We only initiate a pointer drag if the user actually dragged an item, otherwise if they dragged on empty space - // QGraphicsView default behavior would initiate a rubberband drag - - if (clicked_item != nullptr) { - - // Clear snap points - snap_points_.clear(); - - // Record where the drag started in timeline coordinates - track_start_ = parent()->SceneToTrack(drag_start_.y()); - - // Determine whether we're trimming or moving based on the position of the cursor - TimelineViewGhostItem::Mode trim_mode = TimelineViewGhostItem::kNone; - - // FIXME: Hardcoded number - const int kTrimHandle = 20; - - - - if (drag_start_.x() < clicked_item->x() + kTrimHandle) { - trim_mode = TimelineViewGhostItem::kTrimIn; - } else if (drag_start_.x() > clicked_item->x() + clicked_item->rect().right() - kTrimHandle) { - trim_mode = TimelineViewGhostItem::kTrimOut; - } else if (movement_allowed_) { - // Some derived classes don't allow movement - trim_mode = TimelineViewGhostItem::kMove; - } - - // Make sure we can actually perform an action here - if (trim_mode != TimelineViewGhostItem::kNone) { - QList selected_items = parent()->scene_.selectedItems(); - - // If trimming multiple clips, we only trim the earliest in each track (trimming in) or the latest in each track - // (trimming out). If the current clip is NOT one of these, we only trim it. - bool multitrim_enabled = true; - - // Determine if the clicked item is the earliest/latest in the track for in/out trimming respectively - if (trim_mode == TimelineViewGhostItem::kTrimIn || trim_mode == TimelineViewGhostItem::kTrimOut) { - TimelineViewClipItem* clicked_clip = static_cast(clicked_item); - - foreach (QGraphicsItem* item, selected_items) { - TimelineViewClipItem* clip_item = static_cast(item); - - if (clip_item != clicked_item - && clip_item->Track() == clicked_item->Track() - && ((trim_mode == TimelineViewGhostItem::kTrimIn && clip_item->clip()->in() < clicked_clip->clip()->in()) - || (trim_mode == TimelineViewGhostItem::kTrimOut && clip_item->clip()->out() > clicked_clip->clip()->out()))) { - multitrim_enabled = false; - break; - } - } - } - - // For each selected item, create a "ghost", a visual representation of the action before it gets performed - foreach (QGraphicsItem* item, selected_items) { - TimelineViewClipItem* clip_item = dynamic_cast(item); - - - // Determine correct mode for ghost - // - // Movement is indiscriminate, all the ghosts can be set to do this, however trimming is limited to one block - // PER TRACK - - bool include_this_clip = true; - - if (clip_item != clicked_item - && (trim_mode == TimelineViewGhostItem::kTrimIn || trim_mode == TimelineViewGhostItem::kTrimOut)) { - if (multitrim_enabled) { - // Determine if this clip is the earliest/latest in its track - foreach (QGraphicsItem* item, selected_items) { - TimelineViewClipItem* test_clip = static_cast(item); - - if (clip_item != test_clip - && clip_item->Track() == test_clip->Track() - && ((trim_mode == TimelineViewGhostItem::kTrimIn && test_clip->clip()->in() < clip_item->clip()->in()) - || (trim_mode == TimelineViewGhostItem::kTrimOut && test_clip->clip()->out() > clip_item->clip()->out()))) { - include_this_clip = false; - break; - } - } - } else { - include_this_clip = false; - } - } - - if (include_this_clip) { - TimelineViewGhostItem* ghost = TimelineViewGhostItem::FromClip(clip_item); - - ghost->SetScale(parent()->scale_); - ghost->SetMode(trim_mode); - - // Prepare snap points (optimizes snapping for later) - switch (trim_mode) { - case TimelineViewGhostItem::kMove: - snap_points_.append(ghost->In()); - snap_points_.append(ghost->Out()); - break; - case TimelineViewGhostItem::kTrimIn: - snap_points_.append(ghost->In()); - break; - case TimelineViewGhostItem::kTrimOut: - snap_points_.append(ghost->Out()); - break; - default: - break; - } - - parent()->ghost_items_.append(ghost); - parent()->scene_.addItem(ghost); - } - } - } - } + InitiateDrag(event->pos()); // Set dragging to true here so no matter what, the drag isn't re-initiated until it's completed dragging_ = true; @@ -194,52 +75,8 @@ void TimelineView::PointerTool::MouseMove(QMouseEvent *event) } else if (!parent()->ghost_items_.isEmpty()) { // We're already dragging AND we have ghosts to work with + ProcessDrag(event->pos()); - // Retrieve cursor position difference - QPointF scene_pos = GetScenePos(event->pos()); - QPointF movement = scene_pos - drag_start_; - - // Determine track movement - int cursor_track = parent()->SceneToTrack(scene_pos.y()); - int track_movement = cursor_track - track_start_; - - // Determine frame movement - rational time_movement = parent()->SceneToTime(movement.x()); - - // Validate movement (enforce all ghosts moving in legal ways) - time_movement = FrameValidateInternal(time_movement, parent()->ghost_items_); - track_movement = ValidateTrackMovement(track_movement, parent()->ghost_items_); - - // Perform snapping if enabled (adjusts time_movement if it's close to any potential snap points) - if (olive::core.snapping()) { - SnapPoint(snap_points_, &time_movement); - } - - // Perform movement - foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { - switch (ghost->mode()) { - case TimelineViewGhostItem::kNone: - break; - case TimelineViewGhostItem::kTrimIn: - ghost->SetInAdjustment(time_movement); - break; - case TimelineViewGhostItem::kTrimOut: - ghost->SetOutAdjustment(time_movement); - break; - case TimelineViewGhostItem::kMove: - { - ghost->SetInAdjustment(time_movement); - ghost->SetOutAdjustment(time_movement); - - // Track movement is only legal for moving, not for trimming - ghost->SetTrackAdjustment(track_movement); - int track = ghost->GetAdjustedTrack(); - ghost->SetY(parent()->GetTrackY(track)); - ghost->SetHeight(parent()->GetTrackHeight(track)); - break; - } - } - } } } @@ -292,11 +129,11 @@ void TimelineView::PointerTool::MouseReleaseInternal(QMouseEvent *event) foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { Block* b = Node::ValueToPtr(ghost->data(0)); - if (ghost->mode() == TimelineViewGhostItem::kTrimIn || ghost->mode() == TimelineViewGhostItem::kTrimOut) { + if (ghost->mode() == olive::timeline::kTrimIn || ghost->mode() == olive::timeline::kTrimOut) { // If we were trimming, we'll need to change the length // If we were trimming the in point, we'll need to adjust the media in too - if (ghost->mode() == TimelineViewGhostItem::kTrimIn) { + if (ghost->mode() == olive::timeline::kTrimIn) { b->set_media_in(b->media_in() + ghost->InAdjustment()); } @@ -316,3 +153,177 @@ rational TimelineView::PointerTool::FrameValidateInternal(rational time_movement return time_movement; } + +void TimelineView::PointerTool::InitiateDrag(const QPoint& mouse_pos) +{ + // Record where the drag started in timeline coordinates + drag_start_ = GetScenePos(mouse_pos); + + // Get the item that was clicked + TimelineViewClipItem* clicked_item = dynamic_cast(GetItemAtScenePos(drag_start_)); + + // We only initiate a pointer drag if the user actually dragged an item, otherwise if they dragged on empty space + // QGraphicsView default behavior would initiate a rubberband drag + if (clicked_item != nullptr) { + + // Clear snap points + snap_points_.clear(); + + // Record where the drag started in timeline coordinates + track_start_ = parent()->SceneToTrack(drag_start_.y()); + + // Determine whether we're trimming or moving based on the position of the cursor + olive::timeline::MovementMode trim_mode = olive::timeline::kNone; + + // FIXME: Hardcoded number + const int kTrimHandle = 20; + + if (drag_start_.x() < clicked_item->x() + kTrimHandle) { + trim_mode = olive::timeline::kTrimIn; + } else if (drag_start_.x() > clicked_item->x() + clicked_item->rect().right() - kTrimHandle) { + trim_mode = olive::timeline::kTrimOut; + } else if (movement_allowed_) { + // Some derived classes don't allow movement + trim_mode = olive::timeline::kMove; + } + + // Make sure we can actually perform an action here + if (trim_mode != olive::timeline::kNone) { + // Convert selected items list to clips list + QList clips = GetSelectedClips(); + + // If trimming multiple clips, we only trim the earliest in each track (trimming in) or the latest in each track + // (trimming out). If the current clip is NOT one of these, we only trim it. + bool multitrim_enabled = true; + + // Determine if the clicked item is the earliest/latest in the track for in/out trimming respectively + if (trim_mode == olive::timeline::kTrimIn + || trim_mode == olive::timeline::kTrimOut) { + multitrim_enabled = IsClipTrimmable(clicked_item, clips, trim_mode); + } + + // For each selected item, create a "ghost", a visual representation of the action before it gets performed + foreach (TimelineViewClipItem* clip_item, clips) { + // Determine correct mode for ghost + // + // Movement is indiscriminate, all the ghosts can be set to do this, however trimming is limited to one block + // PER TRACK + + bool include_this_clip = true; + + if (clip_item != clicked_item + && (trim_mode == olive::timeline::kTrimIn || trim_mode == olive::timeline::kTrimOut)) { + include_this_clip = multitrim_enabled ? IsClipTrimmable(clip_item, clips, trim_mode) : false; + } + + if (include_this_clip) { + TimelineViewGhostItem* ghost = TimelineViewGhostItem::FromClip(clip_item); + + ghost->SetScale(parent()->scale_); + ghost->SetMode(trim_mode); + + // Prepare snap points (optimizes snapping for later) + switch (trim_mode) { + case olive::timeline::kMove: + snap_points_.append(ghost->In()); + snap_points_.append(ghost->Out()); + break; + case olive::timeline::kTrimIn: + snap_points_.append(ghost->In()); + break; + case olive::timeline::kTrimOut: + snap_points_.append(ghost->Out()); + break; + default: + break; + } + + parent()->ghost_items_.append(ghost); + parent()->scene_.addItem(ghost); + } + } + } + } +} + +void TimelineView::PointerTool::ProcessDrag(const QPoint &mouse_pos) +{ + // Retrieve cursor position difference + QPointF scene_pos = GetScenePos(mouse_pos); + QPointF movement = scene_pos - drag_start_; + + // Determine track movement + int cursor_track = parent()->SceneToTrack(scene_pos.y()); + int track_movement = cursor_track - track_start_; + + // Determine frame movement + rational time_movement = parent()->SceneToTime(movement.x()); + + // Validate movement (enforce all ghosts moving in legal ways) + time_movement = FrameValidateInternal(time_movement, parent()->ghost_items_); + track_movement = ValidateTrackMovement(track_movement, parent()->ghost_items_); + + // Perform snapping if enabled (adjusts time_movement if it's close to any potential snap points) + if (olive::core.snapping()) { + SnapPoint(snap_points_, &time_movement); + } + + // Perform movement + foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { + switch (ghost->mode()) { + case olive::timeline::kNone: + break; + case olive::timeline::kTrimIn: + ghost->SetInAdjustment(time_movement); + break; + case olive::timeline::kTrimOut: + ghost->SetOutAdjustment(time_movement); + break; + case olive::timeline::kMove: + { + ghost->SetInAdjustment(time_movement); + ghost->SetOutAdjustment(time_movement); + + // Track movement is only legal for moving, not for trimming + ghost->SetTrackAdjustment(track_movement); + int track = ghost->GetAdjustedTrack(); + ghost->SetY(parent()->GetTrackY(track)); + ghost->SetHeight(parent()->GetTrackHeight(track)); + break; + } + } + } +} + +QList TimelineView::PointerTool::GetSelectedClips() +{ + QList selected_items = parent()->scene_.selectedItems(); + + // Convert selected items list to clips list + QList clips; + foreach (QGraphicsItem* item, selected_items) { + TimelineViewClipItem* clip_cast = dynamic_cast(item); + + if (clip_cast != nullptr) { + clips.append(clip_cast); + } + } + + return clips; +} + +bool TimelineView::PointerTool::IsClipTrimmable(TimelineViewClipItem* clip, + const QList& items, + const olive::timeline::MovementMode& mode) +{ + foreach (TimelineViewClipItem* compare, items) { + if (clip->Track() == compare->Track() + && clip != compare + && ((compare->clip()->in() < clip->clip()->in() && mode == olive::timeline::kTrimIn) + || (compare->clip()->out() > clip->clip()->out() && mode == olive::timeline::kTrimOut))) { + return false; + } + } + + return true; +} diff --git a/app/widget/timelineview/tool/ripple.cpp b/app/widget/timelineview/tool/ripple.cpp index 65a687ffe..ffc237d68 100644 --- a/app/widget/timelineview/tool/ripple.cpp +++ b/app/widget/timelineview/tool/ripple.cpp @@ -30,26 +30,30 @@ void TimelineView::RippleTool::MouseReleaseInternal(QMouseEvent *event) { Q_UNUSED(event) + if (parent()->ghost_items_.isEmpty()) { + return; + } + // Retrieve cursor position difference QPointF scene_pos = GetScenePos(event->pos()); QPointF movement = scene_pos - drag_start_; - // The point to ripple all clips after (we use the earliest point possible) - rational ripple_point = RATIONAL_MAX; + // For ripple operations, all ghosts will be moving the same way + olive::timeline::MovementMode movement_mode = parent()->ghost_items_.first()->mode(); // The amount to ripple by rational ripple_length = parent()->SceneToTime(movement.x()); + QList blocks_to_ripple; + // Find earliest point to ripple around foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { - if (ghost->mode() == TimelineViewGhostItem::kTrimIn) { - ripple_point = qMin(ripple_point, ghost->In()); - } else if (ghost->mode() == TimelineViewGhostItem::kTrimOut) { - ripple_point = qMin(ripple_point, ghost->Out()); - } + Block* b = Node::ValueToPtr(ghost->data(0)); + + blocks_to_ripple.append(b); } - + emit parent()->RequestRippleBlocks(blocks_to_ripple, ripple_length, movement_mode); } rational TimelineView::RippleTool::FrameValidateInternal(rational time_movement, QVector ghosts) diff --git a/app/widget/timelineview/tool/tool.cpp b/app/widget/timelineview/tool/tool.cpp index f1a34c59c..b5dc87f06 100644 --- a/app/widget/timelineview/tool/tool.cpp +++ b/app/widget/timelineview/tool/tool.cpp @@ -64,7 +64,7 @@ QGraphicsItem *TimelineView::Tool::GetItemAtScenePos(const QPointF &scene_pos) rational TimelineView::Tool::ValidateFrameMovement(rational movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { - if (ghost->mode() != TimelineViewGhostItem::kMove) { + if (ghost->mode() != olive::timeline::kMove) { continue; } @@ -82,7 +82,7 @@ int TimelineView::Tool::ValidateTrackMovement(int movement, const QVectorTrack() + movement < 0) { - if (ghost->mode() != TimelineViewGhostItem::kMove) { + if (ghost->mode() != olive::timeline::kMove) { continue; } @@ -96,7 +96,7 @@ int TimelineView::Tool::ValidateTrackMovement(int movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { - if (ghost->mode() != TimelineViewGhostItem::kTrimIn) { + if (ghost->mode() != olive::timeline::kTrimIn) { continue; } @@ -121,7 +121,7 @@ rational TimelineView::Tool::ValidateInTrimming(rational movement, const QVector rational TimelineView::Tool::ValidateOutTrimming(rational movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { - if (ghost->mode() != TimelineViewGhostItem::kTrimOut) { + if (ghost->mode() != olive::timeline::kTrimOut) { continue; }