transition rewrite mostly done
This commit is contained in:
@@ -55,31 +55,36 @@ void debug_message_handler(QtMsgType type, const QMessageLogContext &context, co
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
fprintf(stderr, "[DEBUG] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
// fprintf(stderr, "[DEBUG] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
fprintf(stderr, "[DEBUG] %s\n", localMsg.constData());
|
||||
if (debug_file.isOpen()) debug_stream << QString("[DEBUG] %1 (%2:%3, %4)\n").arg(localMsg.constData(), context.file, QString::number(context.line), context.function);
|
||||
debug_info.append(QString("<b>[DEBUG]</b> %1 (%2:%3, %4)<br>").arg(localMsg.constData(), context.file, QString::number(context.line), context.function));
|
||||
fflush(stderr);
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
fprintf(stderr, "[INFO] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
// fprintf(stderr, "[INFO] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
fprintf(stderr, "[INFO] %s\n", localMsg.constData());
|
||||
if (debug_file.isOpen()) debug_stream << QString("[INFO] %1 (%2:%3, %4)\n").arg(localMsg.constData(), context.file, QString::number(context.line), context.function);
|
||||
debug_info.append(QString("<b>[INFO]</b> %1 (%2:%3, %4)<br>").arg(localMsg.constData(), context.file, QString::number(context.line), context.function));
|
||||
fflush(stderr);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
fprintf(stderr, "[WARNING] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
// fprintf(stderr, "[WARNING] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
fprintf(stderr, "[WARNING] %s\n", localMsg.constData());
|
||||
if (debug_file.isOpen()) debug_stream << QString("[WARNING] %1 (%2:%3, %4)\n").arg(localMsg.constData(), context.file, QString::number(context.line), context.function);
|
||||
debug_info.append(QString("<font color='yellow'><b>[WARNING]</b> %1 (%2:%3, %4)</font><br>").arg(localMsg.constData(), context.file, QString::number(context.line), context.function));
|
||||
fflush(stderr);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
fprintf(stderr, "[ERROR] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
// fprintf(stderr, "[ERROR] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
fprintf(stderr, "[ERROR] %s\n", localMsg.constData());
|
||||
if (debug_file.isOpen()) debug_stream << QString("[ERROR] %1 (%2:%3, %4)\n").arg(localMsg.constData(), context.file, QString::number(context.line), context.function);
|
||||
debug_info.append(QString("<font color='red'><b>[ERROR]</b> %1 (%2:%3, %4)</font><br>").arg(localMsg.constData(), context.file, QString::number(context.line), context.function));
|
||||
fflush(stderr);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
fprintf(stderr, "[FATAL] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
// fprintf(stderr, "[FATAL] %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
|
||||
fprintf(stderr, "[FATAL] %s\n", localMsg.constData());
|
||||
if (debug_file.isOpen()) debug_stream << QString("[FATAL] %1 (%2:%3, %4)\n").arg(localMsg.constData(), context.file, QString::number(context.line), context.function);
|
||||
debug_info.append(QString("<font color='red'><b>[FATAL]</b> %1 (%2:%3, %4)</font><br>").arg(localMsg.constData(), context.file, QString::number(context.line), context.function));
|
||||
fflush(stderr);
|
||||
|
||||
+4
-5
@@ -1087,6 +1087,9 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
|
||||
stream.writeAttribute("workareaOut", QString::number(s->workarea_out));
|
||||
|
||||
/*
|
||||
QVector<TransitionPtr> transition_save_cache;
|
||||
QVector<int> transition_clip_save_cache;
|
||||
QVector<TransitionType> transition_type_save_cache;
|
||||
for (int j=0;j<s->transitions.size();j++) {
|
||||
TransitionPtr t = s->transitions.at(j);
|
||||
if (t != nullptr) {
|
||||
@@ -1097,7 +1100,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
|
||||
stream.writeEndElement(); // transition
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
for (int j=0;j<s->clips.size();j++) {
|
||||
const ClipPtr& c = s->clips.at(j);
|
||||
@@ -1110,10 +1113,6 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
|
||||
stream.writeAttribute("in", QString::number(c->timeline_in));
|
||||
stream.writeAttribute("out", QString::number(c->timeline_out));
|
||||
stream.writeAttribute("track", QString::number(c->track));
|
||||
/*
|
||||
stream.writeAttribute("opening", QString::number(c->opening_transition));
|
||||
stream.writeAttribute("closing", QString::number(c->closing_transition));
|
||||
*/
|
||||
|
||||
stream.writeAttribute("r", QString::number(c->color_r));
|
||||
stream.writeAttribute("g", QString::number(c->color_g));
|
||||
|
||||
+55
-37
@@ -845,57 +845,73 @@ ClipPtr Timeline::split_clip(ComboAction* ca, bool transitions, int p, long fram
|
||||
|
||||
ClipPtr Timeline::split_clip(ComboAction* ca, bool transitions, int p, long frame, long post_in) {
|
||||
ClipPtr pre = olive::ActiveSequence->clips.at(p);
|
||||
if (pre != nullptr && pre->timeline_in < frame && pre->timeline_out > frame) { // guard against attempts to split at in/out points
|
||||
bool splitting_closing_dual_transition = false;
|
||||
if (pre != nullptr) {
|
||||
|
||||
if (transitions
|
||||
&& pre->get_closing_transition() != nullptr
|
||||
&& pre->get_closing_transition()->secondary_clip != nullptr) {
|
||||
splitting_closing_dual_transition = true;
|
||||
}
|
||||
if (pre->timeline_in < frame && pre->timeline_out > frame) {
|
||||
// duplicate clip without duplicating its transitions, we'll restore them later
|
||||
|
||||
ClipPtr post = ClipPtr(pre->copy(olive::ActiveSequence, transitions && !splitting_closing_dual_transition));
|
||||
ClipPtr post = ClipPtr(pre->copy(olive::ActiveSequence, false));
|
||||
|
||||
long new_clip_length = frame - pre->timeline_in;
|
||||
long new_clip_length = frame - pre->timeline_in;
|
||||
|
||||
post->timeline_in = post_in;
|
||||
post->clip_in = pre->clip_in + (post->timeline_in - pre->timeline_in);
|
||||
post->timeline_in = post_in;
|
||||
post->clip_in = pre->clip_in + (post->timeline_in - pre->timeline_in);
|
||||
|
||||
move_clip(ca, pre, pre->timeline_in, frame, pre->clip_in, pre->track);
|
||||
move_clip(ca, pre, pre->timeline_in, frame, pre->clip_in, pre->track, false);
|
||||
|
||||
if (pre->get_opening_transition() != nullptr) {
|
||||
// if (frame < pre->timeline_in + pre->get_opening_transition()->length && pre->get_opening_transition()->secondary_clip != nullptr) {
|
||||
// separate shared transition
|
||||
// ca->append(new SetPointer((void**) &pre->get_opening_transition()->secondary_clip, nullptr));
|
||||
// pre->get_opening_transition()->secondary_clip->closing_transition = pre->get_opening_transition()->copy(pre->get_opening_transition()->secondary_clip, nullptr);
|
||||
// }
|
||||
if (transitions) {
|
||||
|
||||
if (pre->get_opening_transition()->get_true_length() > new_clip_length) {
|
||||
ca->append(new ModifyTransitionCommand(pre->get_opening_transition(), new_clip_length));
|
||||
}
|
||||
}
|
||||
if (pre->get_closing_transition() != nullptr) {
|
||||
if (splitting_closing_dual_transition) {
|
||||
// just move closing transition to post clip
|
||||
// check if this clip has a closing transition
|
||||
if (pre->closing_transition != nullptr) {
|
||||
|
||||
// WORKAROUND
|
||||
ca->append(new DeleteTransitionCommand(pre->closing_transition));
|
||||
} else {
|
||||
ca->append(new DeleteTransitionCommand(pre->closing_transition));
|
||||
// if so, move closing transition to the post clip
|
||||
post->closing_transition = pre->closing_transition;
|
||||
|
||||
if (post->get_closing_transition() != nullptr) {
|
||||
if (pre->get_closing_transition()->secondary_clip == nullptr) {
|
||||
post->get_closing_transition()->set_length(qMin(long(post->get_closing_transition()->get_true_length()), post->getLength()));
|
||||
// and set the original clip's closing transition to nothing
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&pre->closing_transition), nullptr));
|
||||
|
||||
// and set the transition's reference to the post clip
|
||||
if (post->closing_transition->parent_clip == pre) {
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&post->closing_transition->parent_clip), post.get()));
|
||||
}
|
||||
if (post->closing_transition->secondary_clip == pre) {
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&post->closing_transition->secondary_clip), post.get()));
|
||||
}
|
||||
|
||||
if (post->get_closing_transition()->get_length() > post->getLength()) {
|
||||
post->get_closing_transition()->set_length(post->getLength());
|
||||
// and make sure it's at the correct size to the closing clip
|
||||
if (post->closing_transition != nullptr && post->closing_transition->get_true_length() > post->getLength()) {
|
||||
ca->append(new ModifyTransitionCommand(post->closing_transition, post->getLength()));
|
||||
post->closing_transition->set_length(post->getLength());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// we're keeping the opening clip, so ensure that's a correct size too
|
||||
if (pre->opening_transition != nullptr && pre->opening_transition->get_true_length() > new_clip_length) {
|
||||
ca->append(new ModifyTransitionCommand(pre->opening_transition, new_clip_length));
|
||||
}
|
||||
}
|
||||
|
||||
return post;
|
||||
|
||||
} else if (frame == pre->timeline_in
|
||||
&& pre->opening_transition != nullptr
|
||||
&& pre->opening_transition->secondary_clip != nullptr) {
|
||||
// special case for shared transitions to split it into two
|
||||
|
||||
// set transition to single-clip mode
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&pre->opening_transition->secondary_clip), nullptr));
|
||||
|
||||
// clone transition for other clip
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
pre->opening_transition->secondary_clip,
|
||||
pre->opening_transition,
|
||||
nullptr,
|
||||
0)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -915,11 +931,12 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool
|
||||
|
||||
ClipPtr post = split_clip(ca, true, clip, frame);
|
||||
|
||||
// if alt is not down, split clips links too
|
||||
if (post == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
post_clips.append(post);
|
||||
|
||||
// if alt is not down, split clips links too
|
||||
if (relink) {
|
||||
pre_clips.append(clip);
|
||||
|
||||
@@ -1410,7 +1427,8 @@ bool Timeline::split_selection(ComboAction* ca) {
|
||||
const Selection& s = olive::ActiveSequence->selections.at(i);
|
||||
if (s.track == clip->track) {
|
||||
ClipPtr post_b = split_clip(ca, true, j, s.out);
|
||||
ClipPtr post_a = split_clip(ca, post_b == nullptr, j, s.in);
|
||||
ClipPtr post_a = split_clip(ca, true, j, s.in);
|
||||
|
||||
pre_splits.append(j);
|
||||
post_splits.append(post_a);
|
||||
secondary_post_splits.append(post_b);
|
||||
|
||||
+767
-767
File diff suppressed because it is too large
Load Diff
@@ -85,6 +85,9 @@ void open_clip(ClipPtr clip, bool multithreaded) {
|
||||
}
|
||||
|
||||
void close_clip(ClipPtr clip, bool wait) {
|
||||
// render lock prevents crashes if this function tries to delete a texture while the RenderThread is rendering it
|
||||
clip->render_lock.lock();
|
||||
|
||||
clip->finished_opening = false;
|
||||
|
||||
// destroy opengl texture in main thread
|
||||
@@ -126,6 +129,8 @@ void close_clip(ClipPtr clip, bool wait) {
|
||||
|
||||
clip->open = false;
|
||||
}
|
||||
|
||||
clip->render_lock.unlock();
|
||||
}
|
||||
|
||||
void cache_clip(ClipPtr clip, long playhead, bool reset, bool scrubbing, QVector<ClipPtr>& nests, int playback_speed) {
|
||||
|
||||
@@ -85,15 +85,6 @@ ClipPtr Clip::copy(SequencePtr s, bool duplicate_transitions) {
|
||||
|
||||
copy->cached_fr = (this->sequence == nullptr) ? cached_fr : this->sequence->frame_rate;
|
||||
|
||||
if (duplicate_transitions) {
|
||||
if (get_opening_transition() != nullptr && get_opening_transition()->secondary_clip == nullptr) {
|
||||
copy->opening_transition = get_opening_transition()->copy(copy, nullptr);
|
||||
}
|
||||
if (get_closing_transition() != nullptr && get_closing_transition()->secondary_clip == nullptr) {
|
||||
copy->closing_transition = get_closing_transition()->copy(copy, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
copy->recalculateMaxLength();
|
||||
|
||||
return copy;
|
||||
|
||||
@@ -129,6 +129,7 @@ public:
|
||||
int max_queue_size;
|
||||
QVector<AVFrame*> queue;
|
||||
QMutex queue_lock;
|
||||
QMutex render_lock;
|
||||
QMutex lock;
|
||||
QMutex open_lock;
|
||||
int64_t last_invalid_ts;
|
||||
|
||||
+34
-28
@@ -284,6 +284,7 @@ void AddTransitionCommand::doRedo() {
|
||||
ModifyTransitionCommand::ModifyTransitionCommand(TransitionPtr t, long ilength) {
|
||||
transition_ref_ = t;
|
||||
new_length_ = ilength;
|
||||
old_length_ = transition_ref_->get_true_length();
|
||||
}
|
||||
|
||||
void ModifyTransitionCommand::doUndo() {
|
||||
@@ -291,7 +292,7 @@ void ModifyTransitionCommand::doUndo() {
|
||||
}
|
||||
|
||||
void ModifyTransitionCommand::doRedo() {
|
||||
old_length_ = transition_ref_->get_true_length();
|
||||
|
||||
transition_ref_->set_length(new_length_);
|
||||
}
|
||||
|
||||
@@ -395,6 +396,7 @@ void DeleteMediaCommand::doRedo() {
|
||||
}
|
||||
|
||||
AddClipCommand::AddClipCommand(SequencePtr s, QVector<ClipPtr>& add) {
|
||||
link_offset_ = 0;
|
||||
seq = s;
|
||||
clips = add;
|
||||
}
|
||||
@@ -402,44 +404,48 @@ AddClipCommand::AddClipCommand(SequencePtr s, QVector<ClipPtr>& add) {
|
||||
AddClipCommand::~AddClipCommand() {}
|
||||
|
||||
void AddClipCommand::doUndo() {
|
||||
// clear effects panel
|
||||
panel_effect_controls->clear_effects(true);
|
||||
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = seq->clips.last();
|
||||
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
|
||||
undone_clips.prepend(c);
|
||||
if (c->open) close_clip(c, true);
|
||||
|
||||
if (c != nullptr) {
|
||||
// un-offset all the clips
|
||||
for (int j=0;j<c->linked.size();j++) {
|
||||
c->linked[j] -= link_offset_;
|
||||
}
|
||||
|
||||
// deselect the area occupied by this clip
|
||||
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
|
||||
|
||||
// if the clip is open, close it
|
||||
if (c->open) {
|
||||
close_clip(c, true);
|
||||
}
|
||||
}
|
||||
|
||||
// remove it from the sequence
|
||||
seq->clips.removeLast();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AddClipCommand::doRedo() {
|
||||
if (undone_clips.size() > 0) {
|
||||
for (int i=0;i<undone_clips.size();i++) {
|
||||
seq->clips.append(undone_clips.at(i));
|
||||
}
|
||||
undone_clips.clear();
|
||||
} else {
|
||||
int linkOffset = seq->clips.size();
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr original = clips.at(i);
|
||||
if (original != nullptr) {
|
||||
ClipPtr copy = original->copy(seq);
|
||||
copy->linked.resize(original->linked.size());
|
||||
for (int j=0;j<original->linked.size();j++) {
|
||||
copy->linked[j] = original->linked.at(j) + linkOffset;
|
||||
}
|
||||
if (original->opening_transition != nullptr) {
|
||||
copy->opening_transition = original->get_opening_transition()->copy(copy, nullptr);
|
||||
}
|
||||
if (original->closing_transition != nullptr) {
|
||||
copy->closing_transition = original->get_closing_transition()->copy(copy, nullptr);
|
||||
}
|
||||
seq->clips.append(copy);
|
||||
} else {
|
||||
seq->clips.append(nullptr);
|
||||
link_offset_ = seq->clips.size();
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr original = clips.at(i);
|
||||
|
||||
if (original != nullptr) {
|
||||
|
||||
// offset all links by the current clip size
|
||||
for (int j=0;j<original->linked.size();j++) {
|
||||
original->linked[j] += link_offset_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
seq->clips.append(original);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ public:
|
||||
private:
|
||||
SequencePtr seq;
|
||||
QVector<ClipPtr> clips;
|
||||
QVector<ClipPtr> undone_clips;
|
||||
int link_offset_;
|
||||
};
|
||||
|
||||
class LinkCommand : public OliveAction {
|
||||
|
||||
+548
-542
File diff suppressed because it is too large
Load Diff
+365
-117
@@ -848,7 +848,22 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
|
||||
}
|
||||
}
|
||||
|
||||
void make_room_for_transition(ComboAction* ca, ClipPtr c, int type, long transition_start, long transition_end, bool delete_old_transitions) {
|
||||
void make_room_for_transition(ComboAction* ca,
|
||||
ClipPtr c,
|
||||
int type,
|
||||
long transition_start,
|
||||
long transition_end,
|
||||
bool delete_old_transitions,
|
||||
long timeline_in = -1,
|
||||
long timeline_out = -1) {
|
||||
// it's possible to specify other in/out points for the clip, but default behavior is to use the ones existing
|
||||
if (timeline_in < 0) {
|
||||
timeline_in = c->timeline_in;
|
||||
}
|
||||
if (timeline_out < 0) {
|
||||
timeline_out = c->timeline_out;
|
||||
}
|
||||
|
||||
// make room for transition
|
||||
if (type == kTransitionOpening) {
|
||||
if (delete_old_transitions && c->get_opening_transition() != nullptr) {
|
||||
@@ -875,6 +890,97 @@ void make_room_for_transition(ComboAction* ca, ClipPtr c, int type, long transit
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyTransitionsAfterCreating(ComboAction* ca, ClipPtr open, ClipPtr close, long transition_start, long transition_end) {
|
||||
// in case the user made the transition larger than the clips, we're going to delete everything under
|
||||
// the transition ghost and extend the clips to the transition's coordinates as necessary
|
||||
|
||||
if (open == nullptr && close == nullptr) {
|
||||
qWarning() << "VerifyTransitionsAfterCreating() called with two null clips";
|
||||
return;
|
||||
}
|
||||
|
||||
// determine whether this is a "shared" transition between to clips or not
|
||||
bool shared_transition = (open != nullptr && close != nullptr);
|
||||
|
||||
int track = 0;
|
||||
|
||||
// first we set the clips to "undeletable" so they aren't affected by delete_areas_and_relink()
|
||||
if (open != nullptr) {
|
||||
open->undeletable = true;
|
||||
track = open->track;
|
||||
}
|
||||
if (close != nullptr) {
|
||||
close->undeletable = true;
|
||||
track = close->track;
|
||||
}
|
||||
|
||||
// set the area to delete to the transition's coordinates and clear it
|
||||
QVector<Selection> areas;
|
||||
Selection s;
|
||||
s.in = transition_start;
|
||||
s.out = transition_end;
|
||||
s.track = track;
|
||||
areas.append(s);
|
||||
panel_timeline->delete_areas_and_relink(ca, areas, false);
|
||||
|
||||
// set the clips back to undeletable now that we're done
|
||||
if (open != nullptr) {
|
||||
open->undeletable = false;
|
||||
}
|
||||
if (close != nullptr) {
|
||||
close->undeletable = false;
|
||||
}
|
||||
|
||||
// loop through both kinds of transition
|
||||
for (int t=kTransitionOpening;t<=kTransitionClosing;t++) {
|
||||
|
||||
ClipPtr clip_ref = (t == kTransitionOpening) ? open : close;
|
||||
|
||||
// if we have an opening transition:
|
||||
if (clip_ref != nullptr) {
|
||||
|
||||
// make_room_for_transition will adjust the opposite transition to make space for this one,
|
||||
// for example if the user makes an opening transition that overlaps the closing transition, it'll resize
|
||||
// or even delete the closing transition if necessary (and vice versa)
|
||||
|
||||
make_room_for_transition(ca, clip_ref, t, transition_start, transition_end, true);
|
||||
|
||||
// check if the transition coordinates require the clip to be resized
|
||||
if (transition_start < clip_ref->timeline_in || transition_end > clip_ref->timeline_out) {
|
||||
|
||||
long new_in, new_out;
|
||||
|
||||
if (t == kTransitionOpening) {
|
||||
|
||||
// if the transition is shared, it doesn't matter if the transition extend beyond the in point since
|
||||
// that'll be "absorbed" by the other clip
|
||||
new_in = (shared_transition) ? open->timeline_in : qMin(transition_start, open->timeline_in);
|
||||
|
||||
new_out = qMax(transition_end, open->timeline_out);
|
||||
|
||||
} else {
|
||||
|
||||
new_in = qMin(transition_start, close->timeline_in);
|
||||
|
||||
// if the transition is shared, it doesn't matter if the transition extend beyond the out point since
|
||||
// that'll be "absorbed" by the other clip
|
||||
new_out = (shared_transition) ? close->timeline_out : qMax(transition_end, close->timeline_out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
move_clip(ca,
|
||||
clip_ref,
|
||||
new_in,
|
||||
new_out,
|
||||
clip_ref->clip_in - (clip_ref->timeline_in - new_in),
|
||||
clip_ref->track);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
QToolTip::hideText();
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
@@ -967,6 +1073,10 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
}
|
||||
}
|
||||
} else if (panel_timeline->moving_proc) {
|
||||
|
||||
// see if any clips actually moved, otherwise we don't need to do any processing
|
||||
// (perhaps this could be moved further up to cover more actions?)
|
||||
|
||||
bool process_moving = false;
|
||||
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
@@ -983,54 +1093,70 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
if (process_moving) {
|
||||
const Ghost& first_ghost = panel_timeline->ghosts.at(0);
|
||||
|
||||
// if we were RIPPLING, move all the clips
|
||||
// start a ripple movement
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_RIPPLE) {
|
||||
long ripple_length, ripple_point;
|
||||
|
||||
// ripple_length becomes the length/number of frames we trimmed
|
||||
// ripple point becomes the point to ripple (i.e. the point after or before which we move every clip)
|
||||
if (panel_timeline->trim_type == TRIM_IN) {
|
||||
ripple_length = first_ghost.old_in - first_ghost.in;
|
||||
ripple_point = first_ghost.old_in;
|
||||
// ripple_point is the "axis" around which we move all the clips, any clips after it get moved
|
||||
long ripple_length;
|
||||
long ripple_point = LONG_MAX;
|
||||
|
||||
if (panel_timeline->trim_type == TRIM_IN) {
|
||||
|
||||
// it's assumed that all the ghosts rippled by the same length, so we just take the difference of the
|
||||
// first ghost here
|
||||
ripple_length = first_ghost.old_in - first_ghost.in;
|
||||
|
||||
// for in trimming movements we also move the selections forward (unnecessary for out trimming since
|
||||
// the selected clips more or less stay in the same place)
|
||||
for (int i=0;i<olive::ActiveSequence->selections.size();i++) {
|
||||
olive::ActiveSequence->selections[i].in += ripple_length;
|
||||
olive::ActiveSequence->selections[i].out += ripple_length;
|
||||
}
|
||||
} else {
|
||||
// if we're trimming an out-point
|
||||
|
||||
// use the out points for length if the user trimmed the out point
|
||||
ripple_length = first_ghost.old_out - panel_timeline->ghosts.at(0).out;
|
||||
ripple_point = first_ghost.old_out;
|
||||
|
||||
}
|
||||
|
||||
// build a list of "ignore clips" that won't get affected by ripple_clips() below
|
||||
QVector<int> ignore_clips;
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
|
||||
// push rippled clips forward if necessary
|
||||
// for the same reason that we pushed selections forward above, for in trimming,
|
||||
// we push the ghosts forward here
|
||||
if (panel_timeline->trim_type == TRIM_IN) {
|
||||
ignore_clips.append(g.clip);
|
||||
panel_timeline->ghosts[i].in += ripple_length;
|
||||
panel_timeline->ghosts[i].out += ripple_length;
|
||||
}
|
||||
|
||||
// find the earliest ripple point
|
||||
long comp_point = (panel_timeline->trim_type == TRIM_IN) ? g.old_in : g.old_out;
|
||||
ripple_point = qMin(ripple_point, comp_point);
|
||||
}
|
||||
|
||||
// if this was out trimming, flip the direction of the ripple
|
||||
if (panel_timeline->trim_type == TRIM_OUT) ripple_length = -ripple_length;
|
||||
|
||||
// finally, ripple everything
|
||||
ripple_clips(ca, olive::ActiveSequence, ripple_point, ripple_length, ignore_clips);
|
||||
}
|
||||
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_POINTER
|
||||
&& (event->modifiers() & Qt::AltModifier)
|
||||
&& panel_timeline->trim_target == -1) { // if holding alt (and not trimming), duplicate rather than move
|
||||
// duplicate clips
|
||||
&& panel_timeline->trim_target == -1) {
|
||||
|
||||
// if the user was holding alt (and not trimming), we duplicate clips rather than move them
|
||||
QVector<int> old_clips;
|
||||
QVector<ClipPtr> new_clips;
|
||||
QVector<Selection> delete_areas;
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) {
|
||||
|
||||
// create copy of clip
|
||||
ClipPtr c(olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence));
|
||||
|
||||
@@ -1046,111 +1172,277 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
|
||||
old_clips.append(g.clip);
|
||||
new_clips.append(c);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (new_clips.size() > 0) {
|
||||
|
||||
// delete anything under the new clips
|
||||
panel_timeline->delete_areas_and_relink(ca, delete_areas, false);
|
||||
|
||||
// relink duplicated clips
|
||||
panel_timeline->relink_clips_using_ids(old_clips, new_clips);
|
||||
|
||||
// add them
|
||||
ca->append(new AddClipCommand(olive::ActiveSequence, new_clips));
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// INSERT if holding ctrl
|
||||
|
||||
// if we're not holding alt, this will just be a move
|
||||
|
||||
// if the user is holding ctrl, perform an insert rather than an overwrite
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_POINTER && ctrl) {
|
||||
|
||||
insert_clips(ca);
|
||||
|
||||
} else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_SLIDE) {
|
||||
// move clips
|
||||
|
||||
// if the user is not holding ctrl, we start standard clip movement
|
||||
|
||||
// delete everything under the new clips
|
||||
QVector<Selection> delete_areas;
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
// step 1 - set clips that are moving to "undeletable" (to avoid step 2 deleting any part of them)
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
|
||||
// set clip to undeletable so it's unaffected by delete_areas_and_relink() below
|
||||
olive::ActiveSequence->clips.at(g.clip)->undeletable = true;
|
||||
|
||||
// if the user was moving a transition make sure they're undeletable too
|
||||
if (g.transition != nullptr) {
|
||||
g.transition->parent_clip->undeletable = true;
|
||||
if (g.transition->secondary_clip != nullptr) g.transition->secondary_clip->undeletable = true;
|
||||
if (g.transition->secondary_clip != nullptr) {
|
||||
g.transition->secondary_clip->undeletable = true;
|
||||
}
|
||||
}
|
||||
|
||||
// set area to delete
|
||||
Selection s;
|
||||
s.in = g.in;
|
||||
s.out = g.out;
|
||||
s.track = g.track;
|
||||
delete_areas.append(s);
|
||||
}
|
||||
|
||||
panel_timeline->delete_areas_and_relink(ca, delete_areas, false);
|
||||
|
||||
// clean up, i.e. make everything not undeletable again
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
olive::ActiveSequence->clips.at(g.clip)->undeletable = false;
|
||||
|
||||
if (g.transition != nullptr) {
|
||||
g.transition->parent_clip->undeletable = false;
|
||||
if (g.transition->secondary_clip != nullptr) g.transition->secondary_clip->undeletable = false;
|
||||
if (g.transition->secondary_clip != nullptr) {
|
||||
g.transition->secondary_clip->undeletable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally, perform actual movement of clips
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
Ghost& g = panel_timeline->ghosts[i];
|
||||
|
||||
// step 3 - move clips
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(g.clip);
|
||||
if (g.transition == nullptr) {
|
||||
move_clip(ca, c, (g.in - g.old_in), (g.out - g.old_out), (g.clip_in - g.old_clip_in), (g.track - g.old_track), true, true);
|
||||
|
||||
// adjust transitions if we need to
|
||||
long new_clip_length = (g.out - g.in);
|
||||
if (c->get_opening_transition() != nullptr) {
|
||||
long max_open_length = new_clip_length;
|
||||
if (c->get_closing_transition() != nullptr && panel_timeline->trim_type == TRIM_OUT) {
|
||||
max_open_length -= c->get_closing_transition()->get_true_length();
|
||||
}
|
||||
if (max_open_length <= 0) {
|
||||
ca->append(new DeleteTransitionCommand(c->opening_transition));
|
||||
} else if (c->get_opening_transition()->get_true_length() > max_open_length) {
|
||||
ca->append(new ModifyTransitionCommand(c->opening_transition, max_open_length));
|
||||
}
|
||||
}
|
||||
if (c->get_closing_transition() != nullptr) {
|
||||
long max_open_length = new_clip_length;
|
||||
if (c->get_opening_transition() != nullptr && panel_timeline->trim_type == TRIM_IN) {
|
||||
max_open_length -= c->get_opening_transition()->get_true_length();
|
||||
}
|
||||
if (max_open_length <= 0) {
|
||||
ca->append(new DeleteTransitionCommand(c->closing_transition));
|
||||
} else if (c->get_closing_transition()->get_true_length() > max_open_length) {
|
||||
ca->append(new ModifyTransitionCommand(c->closing_transition, max_open_length));
|
||||
}
|
||||
}
|
||||
if (g.transition == nullptr) {
|
||||
|
||||
// if this was a clip rather than a transition
|
||||
|
||||
move_clip(ca, c, (g.in - g.old_in), (g.out - g.old_out), (g.clip_in - g.old_clip_in), (g.track - g.old_track), false, true);
|
||||
|
||||
} else {
|
||||
|
||||
// if the user was moving a transition
|
||||
|
||||
bool is_opening_transition = (g.transition == c->get_opening_transition());
|
||||
long new_transition_length = g.out - g.in;
|
||||
if (g.transition->secondary_clip != nullptr) new_transition_length >>= 1;
|
||||
ca->append(new ModifyTransitionCommand(is_opening_transition ? c->opening_transition : c->closing_transition, new_transition_length));
|
||||
ca->append(
|
||||
new ModifyTransitionCommand(is_opening_transition ? c->opening_transition : c->closing_transition,
|
||||
new_transition_length)
|
||||
);
|
||||
|
||||
long clip_length = c->getLength();
|
||||
|
||||
if (g.transition->secondary_clip != nullptr) {
|
||||
|
||||
// if this is a shared transition
|
||||
if (g.in != g.old_in && g.trim_type == TRIM_NONE) {
|
||||
long movement = g.in - g.old_in;
|
||||
move_clip(ca, g.transition->parent_clip, movement, 0, movement, 0, false, true);
|
||||
move_clip(ca, g.transition->secondary_clip, 0, movement, 0, 0, false, true);
|
||||
|
||||
// check if the transition is going to extend the out point (opening clip)
|
||||
long timeline_out_movement = 0;
|
||||
if (g.out > g.transition->parent_clip->timeline_out) {
|
||||
timeline_out_movement = g.out - g.transition->parent_clip->timeline_out;
|
||||
}
|
||||
|
||||
// check if the transition is going to extend the in point (closing clip)
|
||||
long timeline_in_movement = 0;
|
||||
if (g.in < g.transition->secondary_clip->timeline_in) {
|
||||
timeline_in_movement = g.in - g.transition->secondary_clip->timeline_in;
|
||||
}
|
||||
|
||||
move_clip(ca, g.transition->parent_clip, movement, timeline_out_movement, movement, 0, false, true);
|
||||
move_clip(ca, g.transition->secondary_clip, timeline_in_movement, movement, timeline_in_movement, 0, false, true);
|
||||
|
||||
make_room_for_transition(ca, g.transition->parent_clip, kTransitionOpening, g.in, g.out, false);
|
||||
make_room_for_transition(ca, g.transition->secondary_clip, kTransitionClosing, g.in, g.out, false);
|
||||
|
||||
}
|
||||
|
||||
} else if (is_opening_transition) {
|
||||
|
||||
if (g.in != g.old_in) {
|
||||
// if transition is going to make the clip bigger, make the clip bigger
|
||||
move_clip(ca, c, (g.in - g.old_in), 0, (g.clip_in - g.old_clip_in), 0, true, true);
|
||||
|
||||
// check if the transition is going to extend the out point
|
||||
long timeline_out_movement = 0;
|
||||
if (g.out > g.transition->parent_clip->timeline_out) {
|
||||
timeline_out_movement = g.out - g.transition->parent_clip->timeline_out;
|
||||
}
|
||||
|
||||
move_clip(ca, c, (g.in - g.old_in), timeline_out_movement, (g.clip_in - g.old_clip_in), 0, false, true);
|
||||
clip_length -= (g.in - g.old_in);
|
||||
}
|
||||
|
||||
make_room_for_transition(ca, c, kTransitionOpening, g.in, g.out, false);
|
||||
|
||||
} else {
|
||||
|
||||
if (g.out != g.old_out) {
|
||||
|
||||
// check if the transition is going to extend the in point
|
||||
long timeline_in_movement = 0;
|
||||
if (g.in < g.transition->parent_clip->timeline_in) {
|
||||
timeline_in_movement = g.in - g.transition->parent_clip->timeline_in;
|
||||
}
|
||||
|
||||
// if transition is going to make the clip bigger, make the clip bigger
|
||||
move_clip(ca, c, 0, (g.out - g.old_out), 0, 0, true, true);
|
||||
move_clip(ca, c, timeline_in_movement, (g.out - g.old_out), timeline_in_movement, 0, false, true);
|
||||
clip_length += (g.out - g.old_out);
|
||||
}
|
||||
|
||||
make_room_for_transition(ca, c, kTransitionClosing, g.in, g.out, false);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// time to verify the transitions of moved clips
|
||||
for (int i=0;i<panel_timeline->ghosts.size();i++) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
|
||||
// only applies to moving clips, transitions are verified above instead
|
||||
if (g.transition == nullptr) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(g.clip);
|
||||
|
||||
long new_clip_length = g.out - g.in;
|
||||
|
||||
// using a for loop between constants to repeat the same steps for the opening and closing transitions
|
||||
for (int t=kTransitionOpening;t<=kTransitionClosing;t++) {
|
||||
|
||||
TransitionPtr transition = (t == kTransitionOpening) ? c->opening_transition : c->closing_transition;
|
||||
|
||||
// check the whether the clip has a transition here
|
||||
if (transition != nullptr) {
|
||||
|
||||
// if the new clip size exceeds the opening transition's length, resize the transition
|
||||
if (new_clip_length < transition->get_true_length()) {
|
||||
ca->append(new ModifyTransitionCommand(transition, new_clip_length));
|
||||
}
|
||||
|
||||
// check if the transition is a shared transition (it'll never have a secondary clip if it isn't)
|
||||
if (transition->secondary_clip != nullptr) {
|
||||
|
||||
// check if the transition's "edge" is going to move
|
||||
if ((t == kTransitionOpening && g.in != g.old_in)
|
||||
|| (t == kTransitionClosing && g.out != g.old_out)) {
|
||||
|
||||
// if we're here, this clip shares its opening transition as the closing transition of another
|
||||
// clip (or vice versa), and the in point is moving, so we may have to account for this
|
||||
|
||||
// the other clip sharing this transition may be moving as well, meaning we don't have to do
|
||||
// anything
|
||||
|
||||
bool split = true;
|
||||
|
||||
// loop through ghosts to find out
|
||||
|
||||
// for a shared transition, the secondary_clip will always be the closing transition side and
|
||||
// the parent_clip will always be the opening transition side
|
||||
ClipPtr search_clip = (t == kTransitionOpening)
|
||||
? transition->secondary_clip : transition->parent_clip;
|
||||
|
||||
for (int j=0;j<panel_timeline->ghosts.size();j++) {
|
||||
const Ghost& other_clip_ghost = panel_timeline->ghosts.at(j);
|
||||
|
||||
if (olive::ActiveSequence->clips.at(other_clip_ghost.clip) == search_clip) {
|
||||
|
||||
// we found the other clip in the current ghosts/selections
|
||||
|
||||
// see if it's destination edge will be equal to this ghost's edge (in which case the
|
||||
// transition doesn't need to change)
|
||||
//
|
||||
// also only do this if j is less than i, because it only needs to happen once and chances are
|
||||
// the other clip already
|
||||
|
||||
bool edges_still_touch;
|
||||
if (t == kTransitionOpening) {
|
||||
edges_still_touch = (other_clip_ghost.out == g.in);
|
||||
} else {
|
||||
edges_still_touch = (other_clip_ghost.in == g.out);
|
||||
}
|
||||
|
||||
if (edges_still_touch || j < i) {
|
||||
split = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (split) {
|
||||
// separate shared transition into one transition for each clip
|
||||
|
||||
if (t == kTransitionOpening) {
|
||||
|
||||
// set transition to single-clip mode
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&transition->secondary_clip),
|
||||
nullptr));
|
||||
|
||||
// create duplicate transition for other clip
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
transition->secondary_clip,
|
||||
transition,
|
||||
nullptr,
|
||||
0));
|
||||
|
||||
} else {
|
||||
|
||||
// set transition to single-clip mode
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&transition->secondary_clip),
|
||||
nullptr));
|
||||
|
||||
// that transition will now attach to the other clip, so we duplicate it for this one
|
||||
|
||||
// create duplicate transition for this clip
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
transition->secondary_clip,
|
||||
transition,
|
||||
nullptr,
|
||||
0));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1164,10 +1456,11 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
// if the transition is greater than 0 length (if it is 0, we make nothing)
|
||||
if (g.in != g.out) {
|
||||
|
||||
// get transition length
|
||||
// get transition coordinates on the timeline
|
||||
long transition_start = qMin(g.in, g.out);
|
||||
long transition_end = qMax(g.in, g.out);
|
||||
|
||||
// get clip references from tool's cached data
|
||||
ClipPtr open = (panel_timeline->transition_tool_open_clip > -1)
|
||||
? olive::ActiveSequence->clips.at(panel_timeline->transition_tool_open_clip)
|
||||
: nullptr;
|
||||
@@ -1176,71 +1469,17 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
? olive::ActiveSequence->clips.at(panel_timeline->transition_tool_close_clip)
|
||||
: nullptr;
|
||||
|
||||
bool shared_transition = (open != nullptr && close != nullptr);
|
||||
|
||||
if (open != nullptr) {
|
||||
open->undeletable = true;
|
||||
}
|
||||
if (close != nullptr) {
|
||||
close->undeletable = true;
|
||||
}
|
||||
|
||||
// delete everything under this new transition
|
||||
QVector<Selection> areas;
|
||||
Selection s;
|
||||
s.in = transition_start;
|
||||
s.out = transition_end;
|
||||
s.track = g.track;
|
||||
areas.append(s);
|
||||
panel_timeline->delete_areas_and_relink(ca, areas, false);
|
||||
|
||||
if (open != nullptr) {
|
||||
open->undeletable = false;
|
||||
}
|
||||
if (close != nullptr) {
|
||||
close->undeletable = false;
|
||||
}
|
||||
|
||||
|
||||
if (open != nullptr) {
|
||||
make_room_for_transition(ca, open, kTransitionOpening, transition_start, transition_end, true);
|
||||
|
||||
if (transition_start < open->timeline_in || transition_end > open->timeline_out) {
|
||||
// long effective_out = (close != nullptr) ? close->timeline_out : open->timeline_out;
|
||||
long new_in = qMin(transition_start, open->timeline_in);
|
||||
long new_out = qMax(transition_end, open->timeline_out);
|
||||
|
||||
move_clip(ca,
|
||||
open,
|
||||
new_in,
|
||||
new_out,
|
||||
open->clip_in - (open->timeline_in - new_in),
|
||||
open->track);
|
||||
}
|
||||
}
|
||||
|
||||
if (close != nullptr) {
|
||||
make_room_for_transition(ca, close, kTransitionClosing, transition_start, transition_end, true);
|
||||
|
||||
if (transition_start < close->timeline_in || transition_end > close->timeline_out) {
|
||||
// long effective_in = (open != nullptr) ? open->timeline_in : close->timeline_in;
|
||||
long new_in = qMin(transition_start, close->timeline_in);
|
||||
long new_out = qMax(transition_end, close->timeline_out);
|
||||
|
||||
move_clip(ca,
|
||||
close,
|
||||
new_in,
|
||||
new_out,
|
||||
close->clip_in - (close->timeline_in - new_in),
|
||||
close->track);
|
||||
}
|
||||
}
|
||||
|
||||
// if it's shared, the transition length is halved (one half for each clip will result in the full length)
|
||||
long transition_length = transition_end - transition_start;
|
||||
if (shared_transition) {
|
||||
if (open != nullptr && close != nullptr) {
|
||||
transition_length /= 2;
|
||||
}
|
||||
|
||||
VerifyTransitionsAfterCreating(ca, open, close, transition_start, transition_end);
|
||||
|
||||
// finally, add the transition to these clips
|
||||
ca->append(new AddTransitionCommand(open,
|
||||
close,
|
||||
nullptr,
|
||||
@@ -1393,7 +1632,9 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(i);
|
||||
|
||||
// snap ghost's in point
|
||||
if (panel_timeline->trim_target == -1 || g.trim_type == TRIM_IN) {
|
||||
if ((panel_timeline->tool != TIMELINE_TOOL_TRANSITION && panel_timeline->trim_target == -1)
|
||||
|| g.trim_type == TRIM_IN
|
||||
|| panel_timeline->transition_tool_open_clip > -1) {
|
||||
fm = g.old_in + frame_diff;
|
||||
if (panel_timeline->snap_to_timeline(&fm, true, true, true)) {
|
||||
frame_diff = fm - g.old_in;
|
||||
@@ -1402,7 +1643,9 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
}
|
||||
|
||||
// snap ghost's out point
|
||||
if (panel_timeline->trim_target == -1 || g.trim_type == TRIM_OUT) {
|
||||
if ((panel_timeline->tool != TIMELINE_TOOL_TRANSITION && panel_timeline->trim_target == -1)
|
||||
|| g.trim_type == TRIM_OUT
|
||||
|| panel_timeline->transition_tool_close_clip > -1) {
|
||||
fm = g.old_out + frame_diff;
|
||||
if (panel_timeline->snap_to_timeline(&fm, true, true, true)) {
|
||||
frame_diff = fm - g.old_out;
|
||||
@@ -1411,7 +1654,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
}
|
||||
|
||||
// if the ghost is attached to a clip, snap its markers too
|
||||
if (panel_timeline->trim_target == -1 && g.clip >= 0) {
|
||||
if (panel_timeline->trim_target == -1 && g.clip >= 0 && panel_timeline->tool != TIMELINE_TOOL_TRANSITION) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(g.clip);
|
||||
for (int j=0;j<c->get_markers().size();j++) {
|
||||
long marker_real_time = c->get_markers().at(j).frame + c->timeline_in - c->clip_in;
|
||||
@@ -1652,7 +1895,8 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
g.in = g.old_in + frame_diff;
|
||||
g.out = g.old_out + frame_diff;
|
||||
|
||||
if (g.transition != nullptr && g.transition == olive::ActiveSequence->clips.at(g.clip)->get_opening_transition()) {
|
||||
if (g.transition != nullptr
|
||||
&& g.transition == olive::ActiveSequence->clips.at(g.clip)->get_opening_transition()) {
|
||||
g.clip_in = g.old_clip_in + frame_diff;
|
||||
}
|
||||
|
||||
@@ -1913,12 +2157,11 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
g.transition = nullptr;
|
||||
|
||||
// check if whole clip is added
|
||||
bool add = is_clip_selected(c, true);
|
||||
bool add = false;
|
||||
|
||||
// if a whole clip is not selected, maybe just a transition is
|
||||
// check if a transition is selected (prioritize transition selection)
|
||||
// (only the pointer tool supports moving transitions)
|
||||
if (!add
|
||||
&& panel_timeline->tool == TIMELINE_TOOL_POINTER
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_POINTER
|
||||
&& (c->get_opening_transition() != nullptr || c->get_closing_transition() != nullptr)) {
|
||||
|
||||
// check if any selections contain a whole transition
|
||||
@@ -1946,6 +2189,11 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
|
||||
}
|
||||
|
||||
// if a transition isn't selected, check if the whole clip is
|
||||
if (!add) {
|
||||
add = is_clip_selected(c, true);
|
||||
}
|
||||
|
||||
if (add) {
|
||||
|
||||
if (g.transition != nullptr) {
|
||||
|
||||
@@ -90,6 +90,8 @@ private:
|
||||
int getScreenPointFromTrack(int track);
|
||||
int getClipIndexFromCoords(long frame, int track);
|
||||
|
||||
void VerifyTransitionHelper();
|
||||
|
||||
bool track_resizing;
|
||||
int track_target;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user