diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 8b973b31c..3a0742f45 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1076,6 +1076,8 @@ void TimelineWidget::ViewTimestampChanged(int64_t ts) void TimelineWidget::ToolChanged() { HideSnaps(); + SetViewBeamCursor(TimelineCoordinate(0, Track::kNone, -1)); + SetViewTransitionOverlay(nullptr, nullptr); } void TimelineWidget::SetViewWaveformsEnabled(bool e) @@ -1147,6 +1149,13 @@ void TimelineWidget::SetViewBeamCursor(const TimelineCoordinate &coord) } } +void TimelineWidget::SetViewTransitionOverlay(ClipBlock *out, ClipBlock *in) +{ + foreach (TimelineAndTrackView* tview, views_) { + tview->view()->SetTransitionOverlay(out, in); + } +} + void TimelineWidget::SetBlockLinksSelected(Block* block, bool selected) { foreach (Block* link, block->block_links()) { diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 971e57866..23853d90f 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -138,6 +138,7 @@ public: Track* GetTrackFromReference(const Track::Reference& ref) const; void SetViewBeamCursor(const TimelineCoordinate& coord); + void SetViewTransitionOverlay(ClipBlock *out, ClipBlock *in); const QVector& GetGhostItems() const { diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index cd9c72717..68d5b386b 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -34,64 +34,49 @@ TransitionTool::TransitionTool(TimelineWidget *parent) : { } +void TransitionTool::HoverMove(TimelineViewMouseEvent *event) +{ + ClipBlock *primary = nullptr; + ClipBlock *secondary = nullptr; + Timeline::MovementMode trim_mode; + rational transition_start_point; + + GetBlocksAtCoord(event->GetCoordinates(), &primary, &secondary, &trim_mode, &transition_start_point); + + if (trim_mode == Timeline::kTrimIn) { + std::swap(primary, secondary); + } + + parent()->SetViewTransitionOverlay(primary, secondary); +} + void TransitionTool::MousePress(TimelineViewMouseEvent *event) { - const Track::Reference& track = event->GetTrack(); - Track* t = parent()->GetTrackFromReference(track); - rational cursor_frame = event->GetFrame(); - - if (!t || t->IsLocked()) { - return; - } - - Block* block_at_time = t->BlockAtTime(event->GetFrame()); - if (!dynamic_cast(block_at_time)) { - return; - } - - // Determine which side of the clip the transition belongs to - rational transition_start_point; + ClipBlock *primary, *secondary; Timeline::MovementMode trim_mode; - rational halfway_point = block_at_time->in() + block_at_time->length() / 2; - rational tenth_point = block_at_time->in() + block_at_time->length() / 10; - Block* other_block = nullptr; - if (cursor_frame < halfway_point) { - transition_start_point = block_at_time->in(); - trim_mode = Timeline::kTrimIn; - - if (cursor_frame < tenth_point - && dynamic_cast(block_at_time->previous())) { - other_block = block_at_time->previous(); - } - } else { - transition_start_point = block_at_time->out(); - trim_mode = Timeline::kTrimOut; - dual_transition_ = (cursor_frame > block_at_time->length() - tenth_point); - - if (cursor_frame > block_at_time->length() - tenth_point - && dynamic_cast(block_at_time->next())) { - other_block = block_at_time->next(); - } + rational transition_start_point; + if (!GetBlocksAtCoord(event->GetCoordinates(), &primary, &secondary, &trim_mode, &transition_start_point)) { + return; } // Create ghost ghost_ = new TimelineViewGhostItem(); - ghost_->SetTrack(track); + ghost_->SetTrack(event->GetTrack()); ghost_->SetIn(transition_start_point); ghost_->SetOut(transition_start_point); ghost_->SetMode(trim_mode); - ghost_->SetData(TimelineViewGhostItem::kAttachedBlock, Node::PtrToValue(block_at_time)); + ghost_->SetData(TimelineViewGhostItem::kAttachedBlock, Node::PtrToValue(primary)); - dual_transition_ = (other_block); - if (other_block) - ghost_->SetData(TimelineViewGhostItem::kReferenceBlock, Node::PtrToValue(other_block)); + dual_transition_ = (secondary); + if (secondary) + ghost_->SetData(TimelineViewGhostItem::kReferenceBlock, Node::PtrToValue(secondary)); parent()->AddGhost(ghost_); snap_points_.append(transition_start_point); // Set the drag start point - drag_start_point_ = cursor_frame; + drag_start_point_ = event->GetFrame(); } void TransitionTool::MouseMove(TimelineViewMouseEvent *event) @@ -175,4 +160,52 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event) } } +bool TransitionTool::GetBlocksAtCoord(const TimelineCoordinate &coord, ClipBlock **primary, ClipBlock **secondary, Timeline::MovementMode *ptrim_mode, rational *start_point) +{ + const Track::Reference& track = coord.GetTrack(); + Track* t = parent()->GetTrackFromReference(track); + rational cursor_frame = coord.GetFrame(); + + if (!t || t->IsLocked()) { + return false; + } + + Block* block_at_time = t->BlockAtTime(coord.GetFrame()); + if (!dynamic_cast(block_at_time)) { + return false; + } + + // Determine which side of the clip the transition belongs to + rational transition_start_point; + Timeline::MovementMode trim_mode; + rational halfway_point = block_at_time->in() + block_at_time->length() / 2; + rational tenth_point = block_at_time->in() + block_at_time->length() / 10; + Block* other_block = nullptr; + if (cursor_frame < halfway_point) { + transition_start_point = block_at_time->in(); + trim_mode = Timeline::kTrimIn; + + if (cursor_frame < tenth_point + && dynamic_cast(block_at_time->previous())) { + other_block = block_at_time->previous(); + } + } else { + transition_start_point = block_at_time->out(); + trim_mode = Timeline::kTrimOut; + dual_transition_ = (cursor_frame > block_at_time->length() - tenth_point); + + if (cursor_frame > block_at_time->length() - tenth_point + && dynamic_cast(block_at_time->next())) { + other_block = block_at_time->next(); + } + } + + *primary = static_cast(block_at_time); + *secondary = static_cast(other_block); + *ptrim_mode = trim_mode; + *start_point = transition_start_point; + + return true; +} + } diff --git a/app/widget/timelinewidget/tool/transition.h b/app/widget/timelinewidget/tool/transition.h index baf485e51..8bae224cf 100644 --- a/app/widget/timelinewidget/tool/transition.h +++ b/app/widget/timelinewidget/tool/transition.h @@ -30,11 +30,17 @@ class TransitionTool : public AddTool public: TransitionTool(TimelineWidget* parent); + virtual void HoverMove(TimelineViewMouseEvent *event) override; + virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; + private: + bool GetBlocksAtCoord(const TimelineCoordinate &coord, ClipBlock **primary, ClipBlock **secondary, Timeline::MovementMode *trim_mode, rational *start_point); + bool dual_transition_; + }; } diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 6d4d787e3..b1a3c364b 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -44,7 +44,9 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : ghosts_(nullptr), show_beam_cursor_(false), connected_track_list_(nullptr), - show_waveforms_(true) + show_waveforms_(true), + transition_overlay_out_(nullptr), + transition_overlay_in_(nullptr) { Q_ASSERT(vertical_alignment == Qt::AlignTop || vertical_alignment == Qt::AlignBottom); setAlignment(Qt::AlignLeft | vertical_alignment); @@ -474,6 +476,31 @@ void TimelineView::DrawBlocks(QPainter *painter, bool foreground) painter->setPen(shadow_color); painter->drawLines(lines); } + + if (transition_overlay_out_ == block || transition_overlay_in_ == block) { + QRectF transition_overlay_rect = r; + + qreal transition_overlay_width = TimeToScene(block->length()) * 0.5; + if (transition_overlay_out_ && transition_overlay_in_) { + // This is a dual transition, use the smallest width + Block *other_block = (transition_overlay_out_ == block) ? transition_overlay_in_ : transition_overlay_out_; + + qreal other_width = TimeToScene(other_block->length()) * 0.5; + + transition_overlay_width = qMin(transition_overlay_width, other_width); + } + + if (transition_overlay_out_ == block) { + transition_overlay_rect.setLeft(transition_overlay_rect.right() - transition_overlay_width); + } else { + transition_overlay_rect.setRight(transition_overlay_rect.left() + transition_overlay_width); + } + + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(0, 0, 0, 64)); + + painter->drawRect(transition_overlay_rect); + } } } @@ -573,6 +600,29 @@ void TimelineView::SetBeamCursor(const TimelineCoordinate &coord) } } +void TimelineView::SetTransitionOverlay(ClipBlock *out, ClipBlock *in) +{ + if (transition_overlay_out_ != out || transition_overlay_in_ != in) { + Track::Type type = Track::kNone; + + if (out) { + type = out->track()->type(); + } else if (in) { + type = in->track()->type(); + } + + if (type == this->connected_track_list_->type()) { + transition_overlay_out_ = out; + transition_overlay_in_ = in; + } else { + transition_overlay_out_ = nullptr; + transition_overlay_in_ = nullptr; + } + + viewport()->update(); + } +} + int TimelineView::SceneToTrack(double y) { int track = -1; diff --git a/app/widget/timelinewidget/view/timelineview.h b/app/widget/timelinewidget/view/timelineview.h index ae0794290..7c5d9fb88 100644 --- a/app/widget/timelinewidget/view/timelineview.h +++ b/app/widget/timelinewidget/view/timelineview.h @@ -55,6 +55,7 @@ public: void ConnectTrackList(TrackList* list); void SetBeamCursor(const TimelineCoordinate& coord); + void SetTransitionOverlay(ClipBlock *out, ClipBlock *in); void SetSelectionList(QHash* s) { @@ -141,6 +142,9 @@ private: bool show_waveforms_; + ClipBlock *transition_overlay_out_; + ClipBlock *transition_overlay_in_; + private slots: void TrackListChanged();