diff --git a/effects/crossdissolvetransition.cpp b/effects/crossdissolvetransition.cpp index c3e68c7eb..4eb2af20c 100644 --- a/effects/crossdissolvetransition.cpp +++ b/effects/crossdissolvetransition.cpp @@ -2,10 +2,7 @@ #include -CrossDissolveTransition::CrossDissolveTransition() { - name = "Cross Dissolve"; - id = VIDEO_DISSOLVE_TRANSITION; -} +CrossDissolveTransition::CrossDissolveTransition() : Transition(VIDEO_DISSOLVE_TRANSITION, "Cross Dissolve") {} void CrossDissolveTransition::process_transition(float progress) { float color[4]; diff --git a/effects/transition.cpp b/effects/transition.cpp index eaca658a0..59637dab0 100644 --- a/effects/transition.cpp +++ b/effects/transition.cpp @@ -4,13 +4,15 @@ #include -Transition::Transition() { +Transition::Transition(int i, QString n) : id(i), name(n) { length = 30; link = NULL; } +Transition::~Transition() {} + Transition* Transition::copy() { - return new Transition(); + return NULL; } void Transition::process_transition(float) {} diff --git a/effects/transition.h b/effects/transition.h index 696133955..39e282ecb 100644 --- a/effects/transition.h +++ b/effects/transition.h @@ -18,10 +18,11 @@ enum AudioTransitions { class Transition { public: - Transition(); - int id; - int length; - QString name; + Transition(int, QString); + ~Transition(); + int id; + QString name; + int length; Transition* link; virtual void process_transition(float); virtual Transition* copy(); diff --git a/mainwindow.cpp b/mainwindow.cpp index b16ad2455..1a50c7aec 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -79,7 +79,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->setupUi(this); - setWindowTitle("Olive (July 2018 | Pre-Alpha)"); + setWindowTitle("Olive (August 2018 | Pre-Alpha)"); statusBar()->showMessage("Welcome to Olive"); ui->centralWidget->setMaximumSize(0, 0); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 2e8be1ce2..fef8e4aea 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -185,18 +185,30 @@ int Timeline::get_track_height_size(bool video) { } void Timeline::add_transition() { + TimelineAction* ta = new TimelineAction(); + bool adding = false; + for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); if (c != NULL && is_clip_selected(c, true)) { if (c->opening_transition == NULL) { - c->opening_transition = create_transition(0, c); + ta->add_transition(sequence, i, 0, TA_OPENING_TRANSITION); + adding = true; } if (c->closing_transition == NULL) { - c->closing_transition = create_transition(0, c); + ta->add_transition(sequence, i, 0, TA_CLOSING_TRANSITION); + adding = true; } } } - redraw_all_clips(true); + + if (adding) { + undo_stack.push(ta); + } else { + delete ta; + } + + redraw_all_clips(true); } int Timeline::calculate_track_height(int track, int value) { @@ -570,7 +582,13 @@ void Timeline::delete_areas_and_relink(TimelineAction* ta, QVector& a for (int j=0;jclip_count();j++) { Clip* c = sequence->get_clip(j); if (c != NULL && c->track == s.track && !c->undeletable) { - if (c->timeline_in >= s.in && c->timeline_out <= s.out) { + if (c->opening_transition != NULL && s.in == c->timeline_in && s.out == c->timeline_in + c->opening_transition->length) { + // delete opening transition + ta->delete_transition(sequence, j, TA_OPENING_TRANSITION); + } else if (c->closing_transition != NULL && s.out == c->timeline_out && s.in == c->timeline_out - c->closing_transition->length) { + // delete closing transition + ta->delete_transition(sequence, j, TA_CLOSING_TRANSITION); + } else if (c->timeline_in >= s.in && c->timeline_out <= s.out) { // clips falls entirely within deletion area ta->delete_clip(sequence, j); } else if (c->timeline_in < s.in && c->timeline_out > s.out) { @@ -929,7 +947,11 @@ void Timeline::snap_to_clip(long* l, bool playhead_inclusive) { break; } else if (snap_to_point(c->timeline_out, l)) { break; - } + } else if (c->opening_transition != NULL && snap_to_point(c->timeline_in + c->opening_transition->length, l)) { + break; + } else if (c->closing_transition != NULL && snap_to_point(c->timeline_in + c->closing_transition->length, l)) { + break; + } } } } diff --git a/panels/timeline.h b/panels/timeline.h index fcbd95839..1615eabb9 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -165,6 +165,7 @@ public: // trimming int trim_target; bool trim_in_point; + int transition_select; // splitting bool splitting; diff --git a/project/undo.cpp b/project/undo.cpp index cfc11d9a4..8bf69049c 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -15,6 +15,8 @@ #include "effects/effects.h" #include "io/media.h" #include "playback/cacher.h" +#include "effects/transition.h" +#include "ui/labelslider.h" QUndoStack undo_stack; @@ -28,6 +30,9 @@ QUndoStack undo_stack; #define TA_ADD_CLIP_IN 7 #define TA_ADD_TRACK 8 #define TA_ADD_EFFECT 9 +#define TA_ADD_TRANSITION 10 +#define TA_MODIFY_TRANSITION 11 +#define TA_DELETE_TRANSITION 12 TimelineAction::TimelineAction() : done(false), @@ -88,48 +93,49 @@ void TimelineAction::add_clips(Sequence* s, QVector& add) { } } -void TimelineAction::new_action(Sequence* s, int action, int clip, long old_val, long new_val) { +void TimelineAction::new_action(Sequence* s, int action, int clip, int transition_type, long old_val, long new_val) { sequences.append(s); actions.append(action); clips.append(clip); + transition_types.append(transition_type); old_values.append(old_val); new_values.append(new_val); } void TimelineAction::set_timeline_in(Sequence* s, int clip, long value) { - new_action(s, TA_IN, clip, s->get_clip(clip)->timeline_in, value); + new_action(s, TA_IN, clip, TA_NO_TRANSITION, s->get_clip(clip)->timeline_in, value); } void TimelineAction::set_timeline_out(Sequence* s, int clip, long value) { - new_action(s, TA_OUT, clip, s->get_clip(clip)->timeline_out, value); + new_action(s, TA_OUT, clip, TA_NO_TRANSITION, s->get_clip(clip)->timeline_out, value); } void TimelineAction::set_clip_in(Sequence* s, int clip, long value) { - new_action(s, TA_CLIP_IN, clip, s->get_clip(clip)->clip_in, value); + new_action(s, TA_CLIP_IN, clip, TA_NO_TRANSITION, s->get_clip(clip)->clip_in, value); } void TimelineAction::set_track(Sequence* s, int clip, int value) { - new_action(s, TA_TRACK, clip, s->get_clip(clip)->track, value); + new_action(s, TA_TRACK, clip, TA_NO_TRANSITION, s->get_clip(clip)->track, value); } void TimelineAction::increase_timeline_in(Sequence* s, int clip, long value) { - new_action(s, TA_ADD_IN, clip, 0, value); + new_action(s, TA_ADD_IN, clip, TA_NO_TRANSITION, 0, value); } void TimelineAction::increase_timeline_out(Sequence* s, int clip, long value) { - new_action(s, TA_ADD_OUT, clip, 0, value); + new_action(s, TA_ADD_OUT, clip, TA_NO_TRANSITION, 0, value); } void TimelineAction::increase_clip_in(Sequence* s, int clip, long value) { - new_action(s, TA_ADD_CLIP_IN, clip, 0, value); + new_action(s, TA_ADD_CLIP_IN, clip, TA_NO_TRANSITION, 0, value); } void TimelineAction::increase_track(Sequence* s, int clip, int value) { - new_action(s, TA_ADD_TRACK, clip, 0, value); + new_action(s, TA_ADD_TRACK, clip, TA_NO_TRANSITION, 0, value); } void TimelineAction::delete_clip(Sequence* s, int clip) { - new_action(s, TA_DELETE, clip, 0, 0); + new_action(s, TA_DELETE, clip, TA_NO_TRANSITION, 0, 0); } void TimelineAction::add_media(QTreeWidgetItem* item, QTreeWidgetItem *parent) { @@ -147,7 +153,19 @@ void TimelineAction::ripple(Sequence* s, long point, long length) { } void TimelineAction::add_effect(Sequence* s, int clip, int effect) { - new_action(s, TA_ADD_EFFECT, clip, 0, effect); + new_action(s, TA_ADD_EFFECT, clip, TA_NO_TRANSITION, 0, effect); +} + +void TimelineAction::add_transition(Sequence* s, int clip, int transition, int type) { + new_action(s, TA_ADD_TRANSITION, clip, type, 0, transition); +} + +void TimelineAction::modify_transition(Sequence* s, int clip, int type, long length) { + new_action(s, TA_MODIFY_TRANSITION, clip, type, 0, length); +} + +void TimelineAction::delete_transition(Sequence* s, int clip, int type) { + new_action(s, TA_DELETE_TRANSITION, clip, type, 0, 0); } void TimelineAction::set_in_out(Sequence* s, bool enabled, long in, long out) { @@ -223,11 +241,47 @@ void TimelineAction::undo() { sequences.at(i)->get_clip(clips.at(i))->track -= new_values.at(i); break; case TA_ADD_EFFECT: + { Clip* c = sequences.at(i)->get_clip(clips.at(i)); Effect* effect = c->effects.at(old_values.at(i)); c->effects.removeAt(old_values.at(i)); delete effect; + } break; + case TA_ADD_TRANSITION: + { + Clip* c = sequences.at(i)->get_clip(clips.at(i)); + if (transition_types.at(i) == TA_OPENING_TRANSITION) { + delete c->opening_transition; + c->opening_transition = NULL; + } else { + delete c->closing_transition; + c->closing_transition = NULL; + } + } + break; + case TA_MODIFY_TRANSITION: + { + Clip* c = sequences.at(i)->get_clip(clips.at(i)); + if (transition_types.at(i) == TA_OPENING_TRANSITION) { + c->opening_transition->length = old_values.at(i); + } else { + c->closing_transition->length = old_values.at(i); + } + } + break; + case TA_DELETE_TRANSITION: + { + Clip* c = sequences.at(i)->get_clip(clips.at(i)); + if (transition_types.at(i) == TA_OPENING_TRANSITION) { + c->opening_transition = create_transition(new_values.at(i), c); + c->opening_transition->length = old_values.at(i); + } else { + c->closing_transition = create_transition(new_values.at(i), c); + c->closing_transition->length = old_values.at(i); + } + } + break; } } @@ -372,6 +426,44 @@ void TimelineAction::redo() { c->effects.append(create_effect(new_values.at(i), c)); } break; + case TA_ADD_TRANSITION: + { + Clip* c = sequences.at(i)->get_clip(clips.at(i)); + if (transition_types.at(i) == TA_OPENING_TRANSITION) { + c->opening_transition = create_transition(new_values.at(i), c); + } else { + c->closing_transition = create_transition(new_values.at(i), c); + } + } + break; + case TA_MODIFY_TRANSITION: + { + Clip* c = sequences.at(i)->get_clip(clips.at(i)); + if (transition_types.at(i) == TA_OPENING_TRANSITION) { + old_values[i] = c->opening_transition->length; + c->opening_transition->length = new_values.at(i); + } else { + old_values[i] = c->closing_transition->length; + c->closing_transition->length = new_values.at(i); + } + } + break; + case TA_DELETE_TRANSITION: + { + Clip* c = sequences.at(i)->get_clip(clips.at(i)); + if (transition_types.at(i) == TA_OPENING_TRANSITION) { + new_values[i] = c->opening_transition->id; + old_values[i] = c->opening_transition->length; + delete c->opening_transition; + c->opening_transition = NULL; + } else { + new_values[i] = c->closing_transition->id; + old_values[i] = c->closing_transition->length; + delete c->closing_transition; + c->closing_transition = NULL; + } + } + break; } } diff --git a/project/undo.h b/project/undo.h index 33047b284..91621af35 100644 --- a/project/undo.h +++ b/project/undo.h @@ -3,6 +3,9 @@ class QTreeWidgetItem; class QCheckBox; +class LabelSlider; +class Effect; +class SourceTable; struct Clip; struct Sequence; struct Media; @@ -11,6 +14,10 @@ struct Media; #include #include +#define TA_NO_TRANSITION 0 +#define TA_OPENING_TRANSITION 1 +#define TA_CLOSING_TRANSITION 2 + extern QUndoStack undo_stack; class TimelineAction : public QUndoCommand { @@ -34,7 +41,10 @@ public: void ripple(Sequence* s, long point, long length); void ripple(Sequence* s, long point, long length, QVector &ignore); void set_in_out(Sequence* s, bool enabled, long in, long out); - void add_effect(Sequence* s, int clip, int effect); + void add_effect(Sequence* s, int clip, int effect); + void add_transition(Sequence* s, int clip, int transition, int type); + void modify_transition(Sequence* s, int clip, int type, long length); + void delete_transition(Sequence* s, int clip, int type); void undo(); void redo(); private: @@ -50,6 +60,7 @@ private: QVector sequences; QVector actions; QVector clips; + QVector transition_types; QVector old_values; QVector new_values; @@ -87,7 +98,7 @@ private: long old_sequence_out; long new_sequence_out; - void new_action(Sequence* s, int action, int clip, long old_val, long new_val); + void new_action(Sequence* s, int action, int clip, int transition_type, long old_val, long new_val); void offset_links(QVector& clips, int offset); bool old_project_changed; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index d427d350c..b660b47e7 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -408,26 +408,18 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { panel_timeline->selections.clear(); } - bool selected_transition = false; Selection s; + s.in = clip->timeline_in; s.out = clip->timeline_out; - if (clip->opening_transition != NULL) { - long open_transition_limit = clip->timeline_in + clip->opening_transition->length; - if (panel_timeline->drag_frame_start < open_transition_limit) { - s.out = open_transition_limit; - selected_transition = true; - } - } - s.in = clip->timeline_in; - if (clip->closing_transition != NULL) { - long close_transition_limit = clip->timeline_out - clip->closing_transition->length; - if (panel_timeline->drag_frame_start > close_transition_limit) { - s.in = close_transition_limit; - selected_transition = true; - } - } + if (panel_timeline->transition_select == TA_OPENING_TRANSITION) { + s.out = clip->timeline_in + clip->opening_transition->length; + } + + if (panel_timeline->transition_select == TA_CLOSING_TRANSITION) { + s.in = clip->timeline_out - clip->closing_transition->length; + } s.track = clip->track; panel_timeline->selections.append(s); @@ -437,7 +429,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { } // if alt is not down, select links - if (!(event->modifiers() & Qt::AltModifier) && !selected_transition) { + if (!(event->modifiers() & Qt::AltModifier) && panel_timeline->transition_select == TA_NO_TRANSITION) { for (int i=0;ilinked.size();i++) { Clip* link = sequence->get_clip(clip->linked.at(i)); if (!panel_timeline->is_clip_selected(link, true)) { @@ -585,11 +577,28 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { for (int i=0;ighosts.size();i++) { Ghost& g = panel_timeline->ghosts[i]; - // step 3 - move clips - ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); - ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); - ta->increase_track(sequence, g.clip, g.track - g.old_track); - ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + // step 3 - move clips + if (g.transition == NULL) { + ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); + ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); + ta->increase_track(sequence, g.clip, g.track - g.old_track); + ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + } else { + Clip* c = sequence->get_clip(g.clip); + bool is_opening_transition = (g.transition == c->opening_transition); + ta->modify_transition( + sequence, + g.clip, + is_opening_transition ? TA_OPENING_TRANSITION : TA_CLOSING_TRANSITION, + g.out - g.in + ); + if (is_opening_transition && g.in != g.old_in) { + ta->increase_timeline_in(sequence, g.clip, g.in - g.old_in); + ta->increase_clip_in(sequence, g.clip, g.clip_in - g.old_clip_in); + } else if (!is_opening_transition && g.out != g.old_out) { + ta->increase_timeline_out(sequence, g.clip, g.out - g.old_out); + } + } } } @@ -709,19 +718,18 @@ void TimelineWidget::init_ghosts() { g.in = g.old_in = c->timeline_out - c->closing_transition->length; g.out = g.old_out = c->timeline_out; g.ghost_length = c->closing_transition->length; + g.clip_in = g.old_clip_in = c->clip_in + c->getLength() - c->closing_transition->length; } - if (panel_timeline->trim_target > -1 || panel_timeline->tool == TIMELINE_TOOL_SLIP || panel_timeline->tool == TIMELINE_TOOL_SLIDE) { - // used for trim ops - switch (c->media_type) { - case MEDIA_TYPE_FOOTAGE: - g.media_length = static_cast(c->media)->get_length_in_frames(sequence->frame_rate); - break; - case MEDIA_TYPE_SEQUENCE: - Sequence* s = static_cast(c->media); - g.media_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, sequence->frame_rate); - break; - } + // used for trim ops + switch (c->media_type) { + case MEDIA_TYPE_FOOTAGE: + g.media_length = static_cast(c->media)->get_length_in_frames(sequence->frame_rate); + break; + case MEDIA_TYPE_SEQUENCE: + Sequence* s = static_cast(c->media); + g.media_length = refactor_frame_number(s->getEndFrame(), s->frame_rate, sequence->frame_rate); + break; } } for (int i=0;iselections.size();i++) { @@ -761,9 +769,10 @@ void validate_snapping(const Ghost& g, long* frame_diff) { for (int j=0;jclip_count();j++) { Clip* c = sequence->get_clip(j); if (c != NULL) { - if (!subvalidate_snapping(g, frame_diff, c->timeline_in)) { - subvalidate_snapping(g, frame_diff, c->timeline_out); - } + if (!subvalidate_snapping(g, frame_diff, c->timeline_in) + && !subvalidate_snapping(g, frame_diff, c->timeline_out) + && (c->opening_transition != NULL && !subvalidate_snapping(g, frame_diff, c->timeline_in + c->opening_transition->length)) + && (c->closing_transition != NULL && !subvalidate_snapping(g, frame_diff, c->timeline_out - c->closing_transition->length))) {} if (panel_timeline->snapped) break; } } @@ -797,6 +806,11 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { Clip* c = NULL; if (g.clip != -1) c = sequence->get_clip(g.clip); + MediaStream* ms = NULL; + if (c->media_type == MEDIA_TYPE_FOOTAGE) { + ms = static_cast(c->media)->get_stream_from_file_index(c->media_stream); + } + // validate ghosts for trimming if (panel_timeline->tool == TIMELINE_TOOL_SLIP) { if (c->media_type == MEDIA_TYPE_SEQUENCE @@ -809,22 +823,15 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { validator += g.ghost_length; if (validator > g.media_length) frame_diff += validator - g.media_length; } - } else if (g.trimming) { - MediaStream* ms = NULL; - if (c->media_type == MEDIA_TYPE_FOOTAGE) { - ms = static_cast(c->media)->get_stream_from_file_index(c->media_stream); - } - + } else if (g.trimming) { if (g.trim_in) { // prevent clip/transition length from being less than 1 frame long validator = g.ghost_length - frame_diff; if (validator < 1) frame_diff -= (1 - validator); - if (g.transition == NULL) { - // prevent timeline in from going below 0 - validator = g.old_in + frame_diff; - if (validator < 0) frame_diff -= validator; - } + // prevent timeline in from going below 0 + validator = g.old_in + frame_diff; + if (validator < 0) frame_diff -= validator; // prevent clip_in from going below 0 if (c->media_type == MEDIA_TYPE_SEQUENCE @@ -841,7 +848,6 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { if (c->media_type == MEDIA_TYPE_SEQUENCE || (ms != NULL && !ms->infinite_length)) { validator = g.old_clip_in + g.ghost_length + frame_diff; - qDebug() << i << validator; if (validator > g.media_length) frame_diff -= validator - g.media_length; } } @@ -877,16 +883,32 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { validator = g.old_in + frame_diff; if (validator < 0) frame_diff -= validator; - // prevent clips from crossing tracks - if (same_sign(g.old_track, panel_timeline->drag_track_start)) { - while (!same_sign(g.old_track, g.old_track + track_diff)) { - if (g.old_track < 0) { - track_diff--; - } else { - track_diff++; - } - } - } + if (g.transition != NULL) { + // prevent clip_in from going below 0 + if (c->media_type == MEDIA_TYPE_SEQUENCE + || (ms != NULL && !ms->infinite_length)) { + validator = g.old_clip_in + frame_diff; + if (validator < 0) frame_diff -= validator; + } + + // prevent clip length exceeding media length + if (c->media_type == MEDIA_TYPE_SEQUENCE + || (ms != NULL && !ms->infinite_length)) { + validator = g.old_clip_in + g.ghost_length + frame_diff; + if (validator > g.media_length) frame_diff -= validator - g.media_length; + } + } + + // prevent clips from crossing tracks + if (same_sign(g.old_track, panel_timeline->drag_track_start)) { + while (!same_sign(g.old_track, g.old_track + track_diff)) { + if (g.old_track < 0) { + track_diff--; + } else { + track_diff++; + } + } + } } } if (temp_frame_diff != frame_diff) panel_timeline->snapped = false; @@ -909,6 +931,10 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { g.in = g.old_in + frame_diff; g.out = g.old_out + frame_diff; + if (g.transition != NULL && g.transition == sequence->get_clip(g.clip)->opening_transition) { + g.clip_in = g.old_clip_in + frame_diff; + } + if (panel_timeline->importing) { if ((panel_timeline->video_ghosts && mouse_track < 0) || (panel_timeline->audio_ghosts && mouse_track >= 0)) { @@ -919,7 +945,7 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { g.track += abs_track_diff; } } - } else if (same_sign(g.old_track, panel_timeline->drag_track_start)) { + } else if (same_sign(g.old_track, panel_timeline->drag_track_start) && panel_timeline->transition_select == TA_NO_TRANSITION) { g.track += track_diff; } } @@ -941,16 +967,18 @@ void TimelineWidget::update_ghosts(QPoint& mouse_pos) { s.in = s.old_in + frame_diff; s.out = s.old_out + frame_diff; s.track = s.old_track; - if (panel_timeline->importing) { - int abs_track_diff = abs(track_diff); - if (s.old_track < 0) { - s.track -= abs_track_diff; - } else { - s.track += abs_track_diff; - } - } else { - if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff; - } + if (panel_timeline->transition_select == TA_NO_TRANSITION) { + if (panel_timeline->importing) { + int abs_track_diff = abs(track_diff); + if (s.old_track < 0) { + s.track -= abs_track_diff; + } else { + s.track += abs_track_diff; + } + } else { + if (same_sign(s.track, panel_timeline->drag_track_start)) s.track += track_diff; + } + } } } } @@ -964,6 +992,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { panel_timeline->cursor_frame = panel_timeline->getFrameFromScreenPoint(event->pos().x()); panel_timeline->cursor_track = getTrackFromScreenPoint(event->pos().y()); + + if (panel_timeline->tool == TIMELINE_TOOL_EDIT || panel_timeline->tool == TIMELINE_TOOL_RAZOR) { panel_timeline->snap_to_clip(&panel_timeline->cursor_frame, !config.edit_tool_also_seeks || !panel_timeline->selecting); } @@ -1322,18 +1352,25 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { bool found = false; bool cursor_contains_clip = false; int closeness = INT_MAX; + panel_timeline->transition_select = TA_NO_TRANSITION; for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); if (c != NULL && c->track == mouse_track) { if (panel_timeline->cursor_frame >= c->timeline_in && panel_timeline->cursor_frame <= c->timeline_out) { cursor_contains_clip = true; + + if (c->opening_transition != NULL && panel_timeline->cursor_frame <= c->timeline_in + c->opening_transition->length) { + panel_timeline->transition_select = TA_OPENING_TRANSITION; + } else if (c->closing_transition != NULL && panel_timeline->cursor_frame >= c->timeline_out - c->closing_transition->length) { + panel_timeline->transition_select = TA_CLOSING_TRANSITION; + } } if (c->timeline_in > mouse_frame_lower && c->timeline_in < mouse_frame_upper) { int nc = qAbs(c->timeline_in + 1 - panel_timeline->cursor_frame); if (nc < closeness) { panel_timeline->trim_target = i; - panel_timeline->trim_in_point = true; + panel_timeline->trim_in_point = true; closeness = nc; found = true; } @@ -1342,11 +1379,40 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { int nc = qAbs(c->timeline_out - 1 - panel_timeline->cursor_frame); if (nc < closeness) { panel_timeline->trim_target = i; - panel_timeline->trim_in_point = false; + panel_timeline->trim_in_point = false; closeness = nc; found = true; } } + if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { + if (c->opening_transition != NULL) { + long transition_point = c->timeline_in + c->opening_transition->length; + + if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { + int nc = qAbs(transition_point + 1 - panel_timeline->cursor_frame); + if (nc < closeness) { + panel_timeline->trim_target = i; + panel_timeline->trim_in_point = false; + panel_timeline->transition_select = TA_OPENING_TRANSITION; + closeness = nc; + found = true; + } + } + } + if (c->closing_transition != NULL) { + long transition_point = c->timeline_out - c->closing_transition->length; + if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { + int nc = qAbs(transition_point - 1 - panel_timeline->cursor_frame); + if (nc < closeness) { + panel_timeline->trim_target = i; + panel_timeline->trim_in_point = true; + panel_timeline->transition_select = TA_CLOSING_TRANSITION; + closeness = nc; + found = true; + } + } + } + } } } if (found) {