transition rewrite mostly done

This commit is contained in:
itsmattkc
2019-02-19 01:16:37 -08:00
parent d1037d4ffa
commit a1619ce8ce
12 changed files with 1792 additions and 1511 deletions
+10 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -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) {
-9
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -236,7 +236,7 @@ public:
private:
SequencePtr seq;
QVector<ClipPtr> clips;
QVector<ClipPtr> undone_clips;
int link_offset_;
};
class LinkCommand : public OliveAction {
+548 -542
View File
File diff suppressed because it is too large Load Diff
+365 -117
View File
@@ -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) {
+2
View File
@@ -90,6 +90,8 @@ private:
int getScreenPointFromTrack(int track);
int getClipIndexFromCoords(long frame, int track);
void VerifyTransitionHelper();
bool track_resizing;
int track_target;