From e785586df28fe7c8179c555967ad48a2818c2056 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 20 Nov 2018 22:02:41 +1100 Subject: [PATCH] transition code rewrite for #110 --- dialogs/newsequencedialog.cpp | 1 + dialogs/replaceclipmediadialog.cpp | 1 + effects/internal/crossdissolvetransition.cpp | 2 +- effects/internal/crossdissolvetransition.h | 4 +- .../internal/exponentialfadetransition.cpp | 2 +- effects/internal/exponentialfadetransition.h | 4 +- effects/internal/linearfadetransition.cpp | 2 +- effects/internal/linearfadetransition.h | 4 +- .../internal/logarithmicfadetransition.cpp | 2 +- effects/internal/logarithmicfadetransition.h | 4 +- mainwindow.cpp | 4 +- olive.pro | 10 +- panels/effectcontrols.cpp | 5 +- panels/panels.cpp | 1 + panels/project.cpp | 46 +- panels/timeline.cpp | 60 +- panels/timeline.h | 3 +- panels/viewer.cpp | 1 + playback/cacher.cpp | 17 +- project/clip.cpp | 41 +- project/clip.h | 7 +- project/effect.cpp | 566 +---------------- project/effect.h | 114 +--- project/effectfield.cpp | 352 +++++++++++ project/effectfield.h | 71 +++ project/effectrow.cpp | 205 +++++++ project/effectrow.h | 54 ++ project/sequence.cpp | 29 +- project/sequence.h | 6 +- project/transition.cpp | 51 ++ project/transition.h | 24 + project/undo.cpp | 578 +----------------- project/undo.h | 9 +- ui/timelinewidget.cpp | 103 ++-- ui/viewerwidget.cpp | 16 +- 35 files changed, 1021 insertions(+), 1378 deletions(-) create mode 100644 project/effectfield.cpp create mode 100644 project/effectfield.h create mode 100644 project/effectrow.cpp create mode 100644 project/effectrow.h create mode 100644 project/transition.cpp create mode 100644 project/transition.h diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 1a52f3879..b3fabd374 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -5,6 +5,7 @@ #include "panels/project.h" #include "project/sequence.h" #include "project/undo.h" +#include "project/clip.h" #include "panels/timeline.h" #include "playback/playback.h" diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp index da378541c..45092104f 100644 --- a/dialogs/replaceclipmediadialog.cpp +++ b/dialogs/replaceclipmediadialog.cpp @@ -5,6 +5,7 @@ #include "panels/timeline.h" #include "panels/project.h" #include "project/sequence.h" +#include "project/clip.h" #include "playback/playback.h" #include "playback/cacher.h" #include "io/media.h" diff --git a/effects/internal/crossdissolvetransition.cpp b/effects/internal/crossdissolvetransition.cpp index 962eefc4c..f71c12637 100644 --- a/effects/internal/crossdissolvetransition.cpp +++ b/effects/internal/crossdissolvetransition.cpp @@ -2,7 +2,7 @@ #include -CrossDissolveTransition::CrossDissolveTransition(Clip* c, const EffectMeta* em) : Effect(c, em) { +CrossDissolveTransition::CrossDissolveTransition(Clip* c, const EffectMeta* em) : Transition(c, em) { enable_coords = true; } diff --git a/effects/internal/crossdissolvetransition.h b/effects/internal/crossdissolvetransition.h index d51766567..907c5566b 100644 --- a/effects/internal/crossdissolvetransition.h +++ b/effects/internal/crossdissolvetransition.h @@ -1,9 +1,9 @@ #ifndef CROSSDISSOLVETRANSITION_H #define CROSSDISSOLVETRANSITION_H -#include "project/effect.h" +#include "project/transition.h" -class CrossDissolveTransition : public Effect { +class CrossDissolveTransition : public Transition { public: CrossDissolveTransition(Clip* c, const EffectMeta* em); void process_coords(double timecode, GLTextureCoords &); diff --git a/effects/internal/exponentialfadetransition.cpp b/effects/internal/exponentialfadetransition.cpp index 55307555f..5333d311f 100644 --- a/effects/internal/exponentialfadetransition.cpp +++ b/effects/internal/exponentialfadetransition.cpp @@ -2,7 +2,7 @@ #include -ExponentialFadeTransition::ExponentialFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {} +ExponentialFadeTransition::ExponentialFadeTransition(Clip* c, const EffectMeta* em) : Transition(c, em) {} void ExponentialFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) { double interval = (timecode_end-timecode_start)/nb_bytes; diff --git a/effects/internal/exponentialfadetransition.h b/effects/internal/exponentialfadetransition.h index 7a44f01cc..0f285503b 100644 --- a/effects/internal/exponentialfadetransition.h +++ b/effects/internal/exponentialfadetransition.h @@ -1,9 +1,9 @@ #ifndef EXPONENTIALFADETRANSITION_H #define EXPONENTIALFADETRANSITION_H -#include "project/effect.h" +#include "project/transition.h" -class ExponentialFadeTransition : public Effect { +class ExponentialFadeTransition : public Transition { public: ExponentialFadeTransition(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/effects/internal/linearfadetransition.cpp b/effects/internal/linearfadetransition.cpp index 3b1f9cc70..8b16b4247 100644 --- a/effects/internal/linearfadetransition.cpp +++ b/effects/internal/linearfadetransition.cpp @@ -1,6 +1,6 @@ #include "linearfadetransition.h" -LinearFadeTransition::LinearFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {} +LinearFadeTransition::LinearFadeTransition(Clip* c, const EffectMeta* em) : Transition(c, em) {} void LinearFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) { double interval = (timecode_end-timecode_start)/nb_bytes; diff --git a/effects/internal/linearfadetransition.h b/effects/internal/linearfadetransition.h index 51b5001be..bfa3bd6ce 100644 --- a/effects/internal/linearfadetransition.h +++ b/effects/internal/linearfadetransition.h @@ -1,9 +1,9 @@ #ifndef LINEARFADETRANSITION_H #define LINEARFADETRANSITION_H -#include "project/effect.h" +#include "project/transition.h" -class LinearFadeTransition : public Effect { +class LinearFadeTransition : public Transition { public: LinearFadeTransition(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/effects/internal/logarithmicfadetransition.cpp b/effects/internal/logarithmicfadetransition.cpp index a19f58c77..d2c1c9c37 100644 --- a/effects/internal/logarithmicfadetransition.cpp +++ b/effects/internal/logarithmicfadetransition.cpp @@ -2,7 +2,7 @@ #include -LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {} +LogarithmicFadeTransition::LogarithmicFadeTransition(Clip* c, const EffectMeta* em) : Transition(c, em) {} void LogarithmicFadeTransition::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int type) { double interval = (timecode_end-timecode_start)/nb_bytes; diff --git a/effects/internal/logarithmicfadetransition.h b/effects/internal/logarithmicfadetransition.h index e5a4a260a..56e9ce370 100644 --- a/effects/internal/logarithmicfadetransition.h +++ b/effects/internal/logarithmicfadetransition.h @@ -1,9 +1,9 @@ #ifndef LOGARITHMICFADETRANSITION_H #define LOGARITHMICFADETRANSITION_H -#include "project/effect.h" +#include "project/transition.h" -class LogarithmicFadeTransition : public Effect { +class LogarithmicFadeTransition : public Transition { public: LogarithmicFadeTransition(Clip* c, const EffectMeta* em); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); diff --git a/mainwindow.cpp b/mainwindow.cpp index a0a584235..c39ed8d6c 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -6,6 +6,8 @@ #include "io/media.h" #include "project/sequence.h" +#include "project/clip.h" +#include "project/undo.h" #include "ui/sourcetable.h" #include "ui/viewerwidget.h" @@ -16,8 +18,6 @@ #include "panels/viewer.h" #include "panels/timeline.h" -#include "project/undo.h" - #include "dialogs/aboutdialog.h" #include "dialogs/newsequencedialog.h" #include "dialogs/exportdialog.h" diff --git a/olive.pro b/olive.pro index 7a1569c82..863337506 100644 --- a/olive.pro +++ b/olive.pro @@ -84,7 +84,10 @@ SOURCES += \ effects/internal/cornerpineffect.cpp \ io/math.cpp \ io/qpainterwrapper.cpp \ - project/effect.cpp + project/effect.cpp \ + project/transition.cpp \ + project/effectrow.cpp \ + project/effectfield.cpp HEADERS += \ mainwindow.h \ @@ -148,7 +151,10 @@ HEADERS += \ effects/internal/cornerpineffect.h \ io/math.h \ io/qpainterwrapper.h \ - project/effect.h + project/effect.h \ + project/transition.h \ + project/effectrow.h \ + project/effectfield.h FORMS += \ mainwindow.ui \ diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 85beb4df5..3dc92a8e8 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -9,6 +9,7 @@ #include "panels/panels.h" #include "project/effect.h" #include "project/clip.h" +#include "project/transition.h" #include "ui/collapsiblewidget.h" #include "project/sequence.h" #include "project/undo.h" @@ -65,10 +66,10 @@ void EffectControls::menu_select(QAction* q) { if ((c->track < 0) == video_menu) { const EffectMeta* meta = reinterpret_cast(q->data().value()); if (transition_menu) { - if (c->opening_transition == NULL) { + if (c->get_opening_transition() == NULL) { ca->append(new AddTransitionCommand(c, meta, TA_OPENING_TRANSITION, 30)); } - if (c->closing_transition == NULL) { + if (c->get_closing_transition() == NULL) { ca->append(new AddTransitionCommand(c, meta, TA_CLOSING_TRANSITION, 30)); } } else { diff --git a/panels/panels.cpp b/panels/panels.cpp index 0698950ab..07e87f288 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -4,6 +4,7 @@ #include "effectcontrols.h" #include "viewer.h" #include "project/sequence.h" +#include "project/clip.h" Project* panel_project = 0; EffectControls* panel_effect_controls = 0; diff --git a/panels/project.cpp b/panels/project.cpp index 684aa3987..d5b6e0bf3 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -7,8 +7,10 @@ #include "panels/viewer.h" #include "playback/playback.h" #include "project/effect.h" +#include "project/transition.h" #include "panels/timeline.h" #include "project/sequence.h" +#include "project/clip.h" #include "io/previewgenerator.h" #include "project/undo.h" #include "mainwindow.h" @@ -1073,8 +1075,8 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } else if (stream.isStartElement() && (stream.name() == "effect" || stream.name() == "opening" || stream.name() == "closing")) { int effect_id = -1; QString effect_name; - bool effect_enabled = true; - int effect_length = -1; + bool effect_enabled = true; + long effect_length = -1; for (int j=0;j -1) e->length = effect_length; - e->set_enabled(effect_enabled); - e->load(stream); + if (tag == "opening" || tag == "closing") { + int transition_index = create_transition(c, meta); + Transition* t = c->sequence->transitions.at(transition_index); + if (effect_length > -1) t->length = effect_length; + t->set_enabled(effect_enabled); + t->load(stream); - if (tag == "opening") { - c->opening_transition = e; - } else if (tag == "closing") { - c->closing_transition = e; + if (tag == "opening") { + c->opening_transition = transition_index; + } else { + c->closing_transition = transition_index; + } } else { + Effect* e = create_effect(c, meta); + if (effect_length > -1) e->length = effect_length; + e->set_enabled(effect_enabled); + e->load(stream); + c->effects.append(e); } } @@ -1449,15 +1459,15 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int stream.writeEndElement(); // effect } - if (c->opening_transition != NULL) { + if (c->get_opening_transition() != NULL) { stream.writeStartElement("opening"); - c->opening_transition->save(stream); + c->get_opening_transition()->save(stream); stream.writeEndElement(); // opening } - if (c->closing_transition != NULL) { + if (c->get_closing_transition() != NULL) { stream.writeStartElement("closing"); // closing - c->closing_transition->save(stream); + c->get_closing_transition()->save(stream); stream.writeEndElement(); // closing } diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 7aafe26f2..05419e760 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -16,6 +16,7 @@ #include "project/undo.h" #include "io/config.h" #include "project/effect.h" +#include "project/transition.h" #include "io/media.h" #include "debug.h" @@ -353,12 +354,12 @@ void Timeline::add_transition() { for (int i=0;iclips.size();i++) { Clip* c = sequence->clips.at(i); if (c != NULL && is_clip_selected(c, true)) { - if (c->opening_transition == NULL) { - ca->append(new AddTransitionCommand(c, get_internal_meta(EFFECT_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30)); + if (c->get_opening_transition() == NULL) { + ca->append(new AddTransitionCommand(c, get_internal_meta(TRANSITION_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30)); adding = true; } - if (c->closing_transition == NULL) { - ca->append(new AddTransitionCommand(c, get_internal_meta(EFFECT_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30)); + if (c->get_closing_transition() == NULL) { + ca->append(new AddTransitionCommand(c, get_internal_meta(TRANSITION_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30)); adding = true; } } @@ -605,18 +606,17 @@ Clip* Timeline::split_clip(ComboAction* ca, int p, long frame, long post_in) { ca->append(new MoveClipAction(pre, pre->timeline_in, frame, pre->clip_in, pre->track)); - if (pre->opening_transition != NULL) { - if (pre->opening_transition->length > new_clip_length) { + if (pre->get_opening_transition() != NULL) { + if (pre->get_opening_transition()->length > new_clip_length) { ca->append(new ModifyTransitionCommand(pre, TA_OPENING_TRANSITION, new_clip_length)); } - delete post->opening_transition; - post->opening_transition = NULL; + post->sequence->hard_delete_transition(post, TA_OPENING_TRANSITION); } - if (pre->closing_transition != NULL) { + if (pre->get_closing_transition() != NULL) { ca->append(new DeleteTransitionCommand(pre, TA_CLOSING_TRANSITION)); - post->closing_transition->length = qMin((long) post->closing_transition->length, post->getLength()); + post->get_closing_transition()->length = qMin((long) post->get_closing_transition()->length, post->getLength()); } return post; @@ -724,10 +724,14 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector& area for (int j=0;jclips.size();j++) { Clip* c = sequence->clips.at(j); if (c != NULL && c->track == s.track && !c->undeletable) { - if (c->opening_transition != NULL && s.in == c->timeline_in && s.out == c->timeline_in + c->opening_transition->length) { + if (c->get_opening_transition() != NULL + && s.in == c->timeline_in + && s.out == c->timeline_in + c->get_opening_transition()->length) { // delete opening transition ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION)); - } else if (c->closing_transition != NULL && s.out == c->timeline_out && s.in == c->timeline_out - c->closing_transition->length) { + } else if (c->get_closing_transition() != NULL + && s.out == c->timeline_out + && s.in == c->timeline_out - c->get_closing_transition()->length) { // delete closing transition ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION)); } else if (c->timeline_in >= s.in && c->timeline_out <= s.out) { @@ -745,22 +749,22 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector& area // only out point is in deletion area ca->append(new MoveClipAction(c, c->timeline_in, s.in, c->clip_in, c->track)); - if (c->closing_transition != NULL) { - if (s.in < c->timeline_out - c->closing_transition->length) { + if (c->get_closing_transition() != NULL) { + if (s.in < c->timeline_out - c->get_closing_transition()->length) { ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION)); } else { - ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, c->closing_transition->length - (c->timeline_out - s.in))); + ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, c->get_closing_transition()->length - (c->timeline_out - s.in))); } } } else if (c->timeline_in < s.out && c->timeline_out > s.out) { // only in point is in deletion area ca->append(new MoveClipAction(c, s.out, c->timeline_out, c->clip_in + (s.out - c->timeline_in), c->track)); - if (c->opening_transition != NULL) { - if (s.out > c->timeline_in + c->opening_transition->length) { + if (c->get_opening_transition() != NULL) { + if (s.out > c->timeline_in + c->get_opening_transition()->length) { ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION)); } else { - ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, c->opening_transition->length - (s.out - c->timeline_in))); + ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, c->get_opening_transition()->length - (s.out - c->timeline_in))); } } } @@ -1015,19 +1019,15 @@ bool Timeline::split_selection(ComboAction* ca) { split_B->timeline_in = s.out; secondary_post_splits.append(split_B); - if (clip->opening_transition != NULL) { - delete split_B->opening_transition; - split_B->opening_transition = NULL; - - delete split_A->opening_transition; - split_A->opening_transition = NULL; + if (clip->get_opening_transition() != NULL) { + split_B->sequence->hard_delete_transition(split_B, TA_OPENING_TRANSITION); + split_A->sequence->hard_delete_transition(split_A, TA_OPENING_TRANSITION); } - if (clip->closing_transition != NULL) { + if (clip->get_closing_transition() != NULL) { ca->append(new DeleteTransitionCommand(clip, TA_CLOSING_TRANSITION)); - delete split_A->closing_transition; - split_A->closing_transition = NULL; + split_A->sequence->hard_delete_transition(split_A, TA_CLOSING_TRANSITION); } ca->append(new MoveClipAction(clip, clip->timeline_in, s.in, clip->clip_in, clip->track)); @@ -1195,9 +1195,11 @@ bool Timeline::snap_to_timeline(long* l, bool use_playhead, bool use_markers, bo return true; } else if (snap_to_point(c->timeline_out, l)) { return true; - } else if (c->opening_transition != NULL && snap_to_point(c->timeline_in + c->opening_transition->length, l)) { + } else if (c->get_opening_transition() != NULL + && snap_to_point(c->timeline_in + c->get_opening_transition()->length, l)) { return true; - } else if (c->closing_transition != NULL && snap_to_point(c->timeline_out - c->closing_transition->length, l)) { + } else if (c->get_closing_transition() != NULL + && snap_to_point(c->timeline_out - c->get_closing_transition()->length, l)) { return true; } } diff --git a/panels/timeline.h b/panels/timeline.h index 5277ca6c8..3bf1a9b10 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -22,6 +22,7 @@ class SourceTable; class ViewerWidget; class ComboAction; class Effect; +class Transition; struct EffectMeta; struct Sequence; struct Clip; @@ -57,7 +58,7 @@ struct Ghost { bool trimming; // transition trimming - Effect* transition; + Transition* transition; }; namespace Ui { diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 1a24a0acc..4a41d26dc 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -5,6 +5,7 @@ #include "timeline.h" #include "panels/project.h" #include "project/sequence.h" +#include "project/clip.h" #include "panels/panels.h" #include "io/config.h" #include "io/media.h" diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 2cab19c74..7f233c31a 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -2,6 +2,7 @@ #include "project/clip.h" #include "project/sequence.h" +#include "project/transition.h" #include "io/media.h" #include "playback/audio.h" #include "playback/playback.h" @@ -47,27 +48,27 @@ void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_ Effect* e = c->effects.at(j); if (e->is_enabled()) e->process_audio(timecode_start, timecode_end, frame->data[0], nb_bytes, 2); } - if (c->opening_transition != NULL) { - if (c->media_type == MEDIA_TYPE_FOOTAGE) { + if (c->get_opening_transition() != NULL) { + if (c->media_type == MEDIA_TYPE_FOOTAGE) { double transition_start = (c->clip_in / c->sequence->frame_rate); - double transition_end = ((c->clip_in + c->opening_transition->length) / c->sequence->frame_rate); + double transition_end = (c->clip_in + c->get_opening_transition()->length) / c->sequence->frame_rate; if (timecode_end < transition_end) { double adjustment = transition_end - transition_start; double adjusted_range_start = (timecode_start - transition_start) / adjustment; double adjusted_range_end = (timecode_end - transition_start) / adjustment; - c->opening_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_OPEN); + c->get_opening_transition()->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_OPEN); } } } - if (c->closing_transition != NULL) { - if (c->media_type == MEDIA_TYPE_FOOTAGE) { - double transition_start = (c->clip_in + c->getLength() - c->closing_transition->length) / c->sequence->frame_rate; + if (c->get_closing_transition() != NULL) { + if (c->media_type == MEDIA_TYPE_FOOTAGE) { + double transition_start = (c->clip_in + c->getLength() - c->get_closing_transition()->length) / c->sequence->frame_rate; double transition_end = (c->clip_in + c->getLength()) / c->sequence->frame_rate; if (timecode_start > transition_start) { double adjustment = transition_end - transition_start; double adjusted_range_start = (timecode_start - transition_start) / adjustment; double adjusted_range_end = (timecode_end - transition_start) / adjustment; - c->closing_transition->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_CLOSE); + c->get_closing_transition()->process_audio(adjusted_range_start, adjusted_range_end, frame->data[0], nb_bytes, TRAN_TYPE_CLOSE); } } } diff --git a/project/clip.cpp b/project/clip.cpp index a0e4dda8f..1137c4fd5 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -1,6 +1,7 @@ #include "clip.h" #include "project/effect.h" +#include "project/transition.h" #include "io/media.h" #include "io/config.h" #include "playback/playback.h" @@ -26,8 +27,8 @@ Clip::Clip(Sequence* s) : reverse(false), maintain_audio_pitch(false), autoscale(config.autoscale_by_default), - opening_transition(NULL), - closing_transition(NULL), + opening_transition(-1), + closing_transition(-1), undeletable(false), replaced(false), ignore_reverse(false), @@ -64,8 +65,8 @@ Clip* Clip::copy(Sequence* s) { copy->effects.append(effects.at(i)->copy(copy)); } - if (opening_transition != NULL) copy->opening_transition = opening_transition->copy(copy); - if (closing_transition != NULL) copy->closing_transition = closing_transition->copy(copy); + if (opening_transition != -1) copy->opening_transition = this->sequence->transitions.at(opening_transition)->copy(copy); + if (closing_transition != -1) copy->closing_transition = this->sequence->transitions.at(closing_transition)->copy(copy); copy->recalculateMaxLength(); @@ -140,7 +141,21 @@ void Clip::queue_remove_earliest() { } } av_frame_free(&queue[earliest_frame]); - queue.removeAt(earliest_frame); + queue.removeAt(earliest_frame); +} + +Transition* Clip::get_opening_transition() { + if (opening_transition > -1) { + return this->sequence->transitions.at(opening_transition); + } + return NULL; +} + +Transition* Clip::get_closing_transition() { + if (closing_transition > -1) { + return this->sequence->transitions.at(closing_transition); + } + return NULL; } Clip::~Clip() { @@ -153,8 +168,8 @@ Clip::~Clip() { } } - if (opening_transition != NULL) delete opening_transition; - if (closing_transition != NULL) delete closing_transition; + //if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION); + //if (closing_transition != -1) this->sequence->hard_delete_transition(this, TA_CLOSING_TRANSITION); for (int i=0;itlink != NULL) { - return timeline_in - opening_transition->tlink->length; + /*if (opening_transition != NULL && opening_transition->tlink != NULL) { + return timeline_in - this->sequence->transitions(opening_transition)->tlink->length; } else { return timeline_in; - } + }*/ + return 0; } long Clip::get_timeline_out_with_transition() { - if (closing_transition != NULL && closing_transition->tlink != NULL) { + /*if (closing_transition != NULL && closing_transition->tlink != NULL) { return timeline_out + closing_transition->tlink->length; } else { return timeline_out; - } + }*/ + return 0; } // timeline functions diff --git a/project/clip.h b/project/clip.h index 70ab4d2b7..6f7fc6fbd 100644 --- a/project/clip.h +++ b/project/clip.h @@ -10,6 +10,7 @@ class Cacher; class Effect; +class Transition; class QOpenGLFramebufferObject; class ComboAction; struct Sequence; @@ -72,8 +73,10 @@ struct Clip // other variables (should be deep copied/duplicated in copy()) QList effects; QVector linked; - Effect* opening_transition; - Effect* closing_transition; + int opening_transition; + Transition* get_opening_transition(); + int closing_transition; + Transition* get_closing_transition(); // media handling AVFormatContext* formatCtx; diff --git a/project/effect.cpp b/project/effect.cpp index 5daa9b136..ca739d990 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -7,19 +7,15 @@ #include "panels/project.h" #include "project/undo.h" #include "project/sequence.h" -#include "ui/labelslider.h" -#include "ui/colorbutton.h" -#include "ui/comboboxex.h" -#include "ui/fontcombobox.h" -#include "ui/checkboxex.h" -#include "ui/texteditex.h" #include "project/clip.h" #include "panels/timeline.h" #include "panels/effectcontrols.h" +#include "ui/checkboxex.h" #include "debug.h" #include "io/path.h" #include "mainwindow.h" #include "io/math.h" +#include "transition.h" #include "effects/internal/transformeffect.h" #include "effects/internal/texteffect.h" @@ -29,10 +25,6 @@ #include "effects/internal/volumeeffect.h" #include "effects/internal/paneffect.h" #include "effects/internal/shakeeffect.h" -#include "effects/internal/crossdissolvetransition.h" -#include "effects/internal/linearfadetransition.h" -#include "effects/internal/exponentialfadetransition.h" -#include "effects/internal/logarithmicfadetransition.h" #include "effects/internal/cornerpineffect.h" #include @@ -64,11 +56,7 @@ Effect* create_effect(Clip* c, const EffectMeta* em) { case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em); case EFFECT_INTERNAL_PAN: return new PanEffect(c, em); case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em); - case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em); - case EFFECT_INTERNAL_CROSSDISSOLVE: return new CrossDissolveTransition(c, em); - case EFFECT_INTERNAL_LINEARFADE: return new LinearFadeTransition(c, em); - case EFFECT_INTERNAL_EXPONENTIALFADE: return new ExponentialFadeTransition(c, em); - case EFFECT_INTERNAL_LOGARITHMICFADE: return new LogarithmicFadeTransition(c, em); + case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em); case EFFECT_INTERNAL_CORNERPIN: return new CornerPinEffect(c, em); } } else { @@ -144,19 +132,19 @@ void load_internal_effects() { em.category = ""; em.name = "Cross Dissolve"; - em.internal = EFFECT_INTERNAL_CROSSDISSOLVE; + em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE; video_effects.append(em); em.name = "Linear Fade"; - em.internal = EFFECT_INTERNAL_LINEARFADE; + em.internal = TRANSITION_INTERNAL_LINEARFADE; audio_effects.append(em); em.name = "Exponential Fade"; - em.internal = EFFECT_INTERNAL_EXPONENTIALFADE; + em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE; audio_effects.append(em); em.name = "Logarithmic Fade"; - em.internal = EFFECT_INTERNAL_LOGARITHMICFADE; + em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE; audio_effects.append(em); } @@ -233,7 +221,6 @@ Effect::Effect(Clip* c, const EffectMeta *em) : parent_clip(c), meta(em), length(30), - tlink(NULL), enable_shader(false), enable_coords(false), enable_superimpose(false), @@ -257,10 +244,6 @@ Effect::Effect(Clip* c, const EffectMeta *em) : // set up UI from effect file container->setText(em->name); - if (em->type == EFFECT_TYPE_TRANSITION) { - add_row("Length:")->add_field(EFFECT_FIELD_DOUBLE); - } - if (!em->filename.isEmpty()) { QFile effect_file(get_effects_dir() + "/" + em->filename); if (effect_file.open(QFile::ReadOnly)) { @@ -682,8 +665,8 @@ void Effect::load(QXmlStreamReader& stream) { void Effect::save(QXmlStreamWriter& stream) { stream.writeAttribute("name", meta->name); - stream.writeAttribute("enabled", QString::number(is_enabled())); - stream.writeAttribute("length", QString::number(length)); + stream.writeAttribute("enabled", QString::number(is_enabled())); + stream.writeAttribute("length", QString::number(length)); for (int i=0;iset_enabled(is_enabled()); - copy->length = length; + copy->set_enabled(is_enabled()); copy_field_keyframes(copy); return copy; } @@ -929,534 +911,6 @@ void Effect::delete_texture() { } } -/* Effect Row Definitions */ - -EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, int row) : - parent_effect(parent), - keyframing(false), - ui(uilayout), - name(n), - ui_row(row), - just_made_unsafe_keyframe(false) -{ - label = new QLabel(name); - ui->addWidget(label, row, 0); - - QSize button_size(20, 20); - QSize icon_size(12, 12); - - QHBoxLayout* key_controls = new QHBoxLayout(); - key_controls->setSpacing(0); - key_controls->setMargin(0); - key_controls->addStretch(); - - left_key_nav = new QPushButton("<"); - left_key_nav->setVisible(false); - left_key_nav->setMaximumSize(button_size); - key_controls->addWidget(left_key_nav); - connect(left_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_previous_key())); - - key_addremove = new QPushButton("."); - key_addremove->setVisible(false); - key_addremove->setMaximumSize(button_size); - key_controls->addWidget(key_addremove); - connect(key_addremove, SIGNAL(clicked(bool)), this, SLOT(toggle_key())); - - right_key_nav = new QPushButton(">"); - right_key_nav->setVisible(false); - right_key_nav->setMaximumSize(button_size); - key_controls->addWidget(right_key_nav); - connect(right_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_next_key())); - - keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), ""); - keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); - keyframe_enable->setMaximumSize(button_size); - keyframe_enable->setIconSize(icon_size); - keyframe_enable->setCheckable(true); - keyframe_enable->setToolTip("Enable Keyframes"); - connect(keyframe_enable, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_enabled(bool))); - connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool))); - key_controls->addWidget(keyframe_enable); - - ui->addLayout(key_controls, row, 6); -} - -bool EffectRow::isKeyframing() { - return keyframing; -} - -void EffectRow::setKeyframing(bool b) { - keyframing = b; - keyframe_enable->setChecked(b); -} - -void EffectRow::set_keyframe_enabled(bool enabled) { - if (enabled) { - set_keyframe_now(true); - } else { - if (QMessageBox::question(panel_effect_controls, "Disable Keyframes", "Disabling keyframes will delete all current keyframes. Are you sure you want to do this?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - // clear - KeyframeDelete* kd = new KeyframeDelete(); - for (int i=keyframe_times.size()-1;i>=0;i--) { - delete_keyframe(kd, i); - } - kd->disable_keyframes_on_row = this; - undo_stack.push(kd); - panel_effect_controls->update_keyframes(); - } else { - setKeyframing(true); - } - } -} - -void EffectRow::keyframe_ui_enabled(bool enabled) { - left_key_nav->setVisible(enabled); - key_addremove->setVisible(enabled); - right_key_nav->setVisible(enabled); -} - -void EffectRow::goto_previous_key() { - long key = LONG_MIN; - Clip* c = parent_effect->parent_clip; - for (int i=0;iclip_in + c->timeline_in; - if (comp < sequence->playhead) { - key = qMax(comp, key); - } - } - if (key != LONG_MIN) panel_sequence_viewer->seek(key); -} - -void EffectRow::toggle_key() { - int index = -1; - Clip* c = parent_effect->parent_clip; - for (int i=0;itimeline_in - c->clip_in + keyframe_times.at(i); - if (comp == sequence->playhead) { - index = i; - break; - } - } - if (index < 0) { - // keyframe doesn't exist, set one - set_keyframe_now(true); - } else { - KeyframeDelete* kd = new KeyframeDelete(); - delete_keyframe(kd, index); - undo_stack.push(kd); - panel_effect_controls->update_keyframes(); - panel_sequence_viewer->viewer_widget->update(); - } -} - -void EffectRow::goto_next_key() { - long key = LONG_MAX; - Clip* c = parent_effect->parent_clip; - for (int i=0;itimeline_in - c->clip_in + keyframe_times.at(i); - if (comp > sequence->playhead) { - key = qMin(comp, key); - } - } - if (key != LONG_MAX) panel_sequence_viewer->seek(key); -} - -EffectField* EffectRow::add_field(int type, int colspan) { - EffectField* field = new EffectField(this, type); - fields.append(field); - QWidget* element = field->get_ui_element(); - ui->addWidget(element, ui_row, fields.size(), 1, colspan); - return field; -} - -EffectRow::~EffectRow() { - for (int i=0;iplayhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in; - for (int i=0;iredo(); - delete ks; - } - - panel_effect_controls->update_keyframes(); -} - -void EffectRow::delete_keyframe_at_time(KeyframeDelete* kd, long time) { - for (int i=0;irows.append(this); - kd->keyframes.append(index); -} - -EffectField* EffectRow::field(int i) { - return fields.at(i); -} - -int EffectRow::fieldCount() { - return fields.size(); -} - -/* Effect Field Definitions */ - -EffectField::EffectField(EffectRow *parent, int t) : parent_row(parent), type(t) { - switch (t) { - case EFFECT_FIELD_DOUBLE: - { - LabelSlider* ls = new LabelSlider(); - ui_element = ls; - connect(ls, SIGNAL(valueChanged()), this, SLOT(uiElementChange())); - } - break; - case EFFECT_FIELD_COLOR: - { - ColorButton* cb = new ColorButton(); - ui_element = cb; - connect(cb, SIGNAL(color_changed()), this, SLOT(uiElementChange())); - } - break; - case EFFECT_FIELD_STRING: - { - TextEditEx* edit = new TextEditEx(); - edit->setUndoRedoEnabled(true); - ui_element = edit; - connect(edit, SIGNAL(textChanged()), this, SLOT(uiElementChange())); - } - break; - case EFFECT_FIELD_BOOL: - { - CheckboxEx* cb = new CheckboxEx(); - ui_element = cb; - connect(cb, SIGNAL(clicked(bool)), this, SLOT(uiElementChange())); - connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); - } - break; - case EFFECT_FIELD_COMBO: - { - ComboBoxEx* cb = new ComboBoxEx(); - ui_element = cb; - connect(cb, SIGNAL(activated(int)), this, SLOT(uiElementChange())); - } - break; - case EFFECT_FIELD_FONT: - { - FontCombobox* fcb = new FontCombobox(); - ui_element = fcb; - connect(fcb, SIGNAL(activated(int)), this, SLOT(uiElementChange())); - } - break; - } -} - -QVariant EffectField::get_previous_data() { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->getPreviousValue(); break; - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->getPreviousValue(); break; - case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPreviousValue(); break; - case EFFECT_FIELD_BOOL: return !static_cast(ui_element)->isChecked(); break; - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->getPreviousIndex(); break; - case EFFECT_FIELD_FONT: return static_cast(ui_element)->getPreviousValue(); break; - } - return QVariant(); -} - -QVariant EffectField::get_current_data() { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->value(); break; - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->get_color(); break; - case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPlainTextEx(); break; - case EFFECT_FIELD_BOOL: return static_cast(ui_element)->isChecked(); break; - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->currentIndex(); break; - case EFFECT_FIELD_FONT: return static_cast(ui_element)->currentText(); break; - } - return QVariant(); -} - -double EffectField::frameToTimecode(long frame) { - return ((double) frame / parent_row->parent_effect->parent_clip->sequence->frame_rate); -} - -long EffectField::timecodeToFrame(double timecode) { - return qRound(timecode * parent_row->parent_effect->parent_clip->sequence->frame_rate); -} - -void EffectField::set_current_data(const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->set_value(data.toDouble(), false); break; - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->set_color(data.value()); break; - case EFFECT_FIELD_STRING: return static_cast(ui_element)->setPlainTextEx(data.toString()); break; - case EFFECT_FIELD_BOOL: return static_cast(ui_element)->setChecked(data.toBool()); break; - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->setCurrentIndexEx(data.toInt()); break; - case EFFECT_FIELD_FONT: return static_cast(ui_element)->setCurrentTextEx(data.toString()); break; - } -} - -void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { - int before_keyframe_index = -1; - int after_keyframe_index = -1; - long before_keyframe_time = LONG_MIN; - long after_keyframe_time = LONG_MAX; - long frame = timecodeToFrame(timecode); - - for (int i=0;ikeyframe_times.size();i++) { - long eval_keyframe_time = parent_row->keyframe_times.at(i); - if (eval_keyframe_time == frame) { - before = i; - after = i; - return; - } else if (eval_keyframe_time < frame && eval_keyframe_time > before_keyframe_time) { - before_keyframe_index = i; - before_keyframe_time = eval_keyframe_time; - } else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) { - after_keyframe_index = i; - after_keyframe_time = eval_keyframe_time; - } - } - - if ((type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) { - // interpolate - before = before_keyframe_index; - after = after_keyframe_index; - - progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); - - // TODO routines for bezier - currently this is purely linear - } else if (before_keyframe_index > -1) { - before = before_keyframe_index; - after = before_keyframe_index; - } else { - before = after_keyframe_index; - after = after_keyframe_index; - } -} - -bool EffectField::hasKeyframes() { - return (parent_row->isKeyframing() && keyframe_data.size() > 0); -} - -QVariant EffectField::validate_keyframe_data(double timecode, bool async) { - if (hasKeyframes()) { - int before_keyframe; - int after_keyframe; - double progress; - get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); - - int kf_type = (progress < 0.5) ? parent_row->keyframe_types.at(before_keyframe) : parent_row->keyframe_types.at(after_keyframe); - if (kf_type == KEYFRAME_TYPE_SMOOTH) { - double b = 4; - double c = 1.313; - double x = (b * progress) - (b*0.5); - progress = (c*(qPow(M_E, x)/(qPow(M_E, x) + 1)))-((c-1)*0.5); - } - - const QVariant& before_data = keyframe_data.at(before_keyframe); - switch (type) { - case EFFECT_FIELD_DOUBLE: - { - double value; - if (before_keyframe == after_keyframe) { - value = keyframe_data.at(before_keyframe).toDouble(); - } else { - double before_dbl = keyframe_data.at(before_keyframe).toDouble(); - double after_dbl = keyframe_data.at(after_keyframe).toDouble(); - value = double_lerp(before_dbl, after_dbl, progress); - } - if (async) { - return value; - } - static_cast(ui_element)->set_value(value, false); - } - break; - case EFFECT_FIELD_COLOR: - { - QColor value; - if (before_keyframe == after_keyframe) { - value = keyframe_data.at(before_keyframe).value(); - } else { - QColor before_data = keyframe_data.at(before_keyframe).value(); - QColor after_data = keyframe_data.at(after_keyframe).value(); - value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); - } - if (async) { - return value; - } - static_cast(ui_element)->set_color(value); - } - break; - case EFFECT_FIELD_STRING: - if (async) { - return before_data; - } - static_cast(ui_element)->setPlainTextEx(before_data.toString()); - break; - case EFFECT_FIELD_BOOL: - if (async) { - return before_data; - } - static_cast(ui_element)->setChecked(before_data.toBool()); - break; - case EFFECT_FIELD_COMBO: - if (async) { - return before_data; - } - static_cast(ui_element)->setCurrentIndexEx(before_data.toInt()); - break; - case EFFECT_FIELD_FONT: - if (async) { - return before_data; - } - static_cast(ui_element)->setCurrentTextEx(before_data.toString()); - break; - } - } - return QVariant(); -} - -void EffectField::uiElementChange() { - bool enableKeyframes = !(type == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); - if (parent_row->isKeyframing()) { - parent_row->set_keyframe_now(enableKeyframes); - } else if (enableKeyframes) { - // set undo - undo_stack.push(new EffectFieldUndo(this)); - } - emit changed(); -} - -QWidget* EffectField::get_ui_element() { - return ui_element; -} - -void EffectField::set_enabled(bool e) { - ui_element->setEnabled(e); -} - -double EffectField::get_double_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toDouble(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->value(); -} - -void EffectField::set_double_value(double v) { - static_cast(ui_element)->set_value(v, false); -} - -void EffectField::set_double_default_value(double v) { - static_cast(ui_element)->set_default_value(v); -} - -void EffectField::set_double_minimum_value(double v) { - static_cast(ui_element)->set_minimum_value(v); -} - -void EffectField::set_double_maximum_value(double v) { - static_cast(ui_element)->set_maximum_value(v); -} - -void EffectField::add_combo_item(const QString& name, const QVariant& data) { - static_cast(ui_element)->addItem(name, data); -} - -int EffectField::get_combo_index(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toInt(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentIndex(); -} - -const QVariant EffectField::get_combo_data(double timecode) { - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentData(); -} - -const QString EffectField::get_combo_string(double timecode) { - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentText(); -} - -void EffectField::set_combo_index(int index) { - static_cast(ui_element)->setCurrentIndexEx(index); -} - -void EffectField::set_combo_string(const QString& s) { - static_cast(ui_element)->setCurrentTextEx(s); -} - -bool EffectField::get_bool_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toBool(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->isChecked(); -} - -void EffectField::set_bool_value(bool b) { - return static_cast(ui_element)->setChecked(b); -} - -const QString EffectField::get_string_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->getPlainTextEx(); -} - -void EffectField::set_string_value(const QString& s) { - static_cast(ui_element)->setPlainTextEx(s); -} - -const QString EffectField::get_font_name(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentText(); -} - -void EffectField::set_font_name(const QString& s) { - static_cast(ui_element)->setCurrentText(s); -} - -QColor EffectField::get_color_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).value(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->get_color(); -} - -void EffectField::set_color_value(QColor color) { - static_cast(ui_element)->set_color(color); -} - qint16 mix_audio_sample(qint16 a, qint16 b) { qint32 mixed_sample = static_cast(a) + static_cast(b); mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); diff --git a/project/effect.h b/project/effect.h index c722c36b9..2f467f1b5 100644 --- a/project/effect.h +++ b/project/effect.h @@ -48,13 +48,6 @@ extern QMutex effects_loaded; #define EFFECT_TYPE_EFFECT 3 #define EFFECT_TYPE_TRANSITION 4 -#define EFFECT_FIELD_DOUBLE 0 -#define EFFECT_FIELD_COLOR 1 -#define EFFECT_FIELD_STRING 2 -#define EFFECT_FIELD_BOOL 3 -#define EFFECT_FIELD_COMBO 4 -#define EFFECT_FIELD_FONT 5 - #define EFFECT_KEYFRAME_LINEAR 0 #define EFFECT_KEYFRAME_HOLD 1 #define EFFECT_KEYFRAME_BEZIER 2 @@ -67,10 +60,10 @@ extern QMutex effects_loaded; #define EFFECT_INTERNAL_PAN 5 #define EFFECT_INTERNAL_TONE 6 #define EFFECT_INTERNAL_SHAKE 7 -#define EFFECT_INTERNAL_CROSSDISSOLVE 8 -#define EFFECT_INTERNAL_LINEARFADE 9 -#define EFFECT_INTERNAL_EXPONENTIALFADE 10 -#define EFFECT_INTERNAL_LOGARITHMICFADE 11 + + + + #define EFFECT_INTERNAL_CORNERPIN 12 #define EFFECT_INTERNAL_COUNT 13 @@ -107,99 +100,8 @@ struct GLTextureCoords { qint16 mix_audio_sample(qint16 a, qint16 b); -class EffectField : public QObject { - Q_OBJECT -public: - EffectField(EffectRow* parent, int t); - EffectRow* parent_row; - int type; - QString id; - - QVariant get_previous_data(); - QVariant get_current_data(); - double frameToTimecode(long frame); - long timecodeToFrame(double timecode); - void set_current_data(const QVariant&); - void get_keyframe_data(double timecode, int& before, int& after, double& d); - QVariant validate_keyframe_data(double timecode, bool async = false); - - double get_double_value(double timecode, bool async = false); - void set_double_value(double v); - void set_double_default_value(double v); - void set_double_minimum_value(double v); - void set_double_maximum_value(double v); - - const QString get_string_value(double timecode, bool async = false); - void set_string_value(const QString &s); - - void add_combo_item(const QString& name, const QVariant &data); - int get_combo_index(double timecode, bool async = false); - const QVariant get_combo_data(double timecode); - const QString get_combo_string(double timecode); - void set_combo_index(int index); - void set_combo_string(const QString& s); - - bool get_bool_value(double timecode, bool async = false); - void set_bool_value(bool b); - - const QString get_font_name(double timecode, bool async = false); - void set_font_name(const QString& s); - - QColor get_color_value(double timecode, bool async = false); - void set_color_value(QColor color); - - QWidget* get_ui_element(); - void set_enabled(bool e); - QVector keyframe_data; - QWidget* ui_element; -private: - bool hasKeyframes(); -private slots: - void uiElementChange(); -signals: - void changed(); - void toggled(bool); -}; - -class EffectRow : public QObject { - Q_OBJECT -public: - EffectRow(Effect* parent, QGridLayout* uilayout, const QString& n, int row); - ~EffectRow(); - EffectField* add_field(int type, int colspan = 1); - EffectField* field(int i); - int fieldCount(); - void set_keyframe_now(bool undoable); - void delete_keyframe(KeyframeDelete *kd, int index); - void delete_keyframe_at_time(KeyframeDelete* kd, long time); - QLabel* label; - Effect* parent_effect; - - bool isKeyframing(); - void setKeyframing(bool); - - QVector keyframe_times; - QVector keyframe_types; -private slots: - void set_keyframe_enabled(bool); - void keyframe_ui_enabled(bool); - void goto_previous_key(); - void toggle_key(); - void goto_next_key(); -private: - bool keyframing; - QGridLayout* ui; - QString name; - int ui_row; - QVector fields; - - QPushButton* keyframe_enable; - QPushButton* left_key_nav; - QPushButton* key_addremove; - QPushButton* right_key_nav; - - bool just_made_unsafe_keyframe; -}; +#include "effectfield.h" +#include "effectrow.h" class Effect : public QObject { Q_OBJECT @@ -208,13 +110,11 @@ public: ~Effect(); Clip* parent_clip; const EffectMeta* meta; + long length; // used only for transitions int id; QString name; CollapsibleWidget* container; - long length; // only used for transitions - Effect* tlink; - EffectRow* add_row(const QString &name); EffectRow* row(int i); int row_count(); diff --git a/project/effectfield.cpp b/project/effectfield.cpp new file mode 100644 index 000000000..7cffe89e6 --- /dev/null +++ b/project/effectfield.cpp @@ -0,0 +1,352 @@ +#include "effectfield.h" + +#include "ui/labelslider.h" +#include "ui/colorbutton.h" +#include "ui/texteditex.h" +#include "ui/checkboxex.h" +#include "ui/comboboxex.h" +#include "ui/fontcombobox.h" + +#include "effectrow.h" +#include "effect.h" + +#include "project/undo.h" +#include "project/clip.h" +#include "project/sequence.h" + +#include "io/math.h" +#include + +EffectField::EffectField(EffectRow *parent, int t) : parent_row(parent), type(t) { + switch (t) { + case EFFECT_FIELD_DOUBLE: + { + LabelSlider* ls = new LabelSlider(); + ui_element = ls; + connect(ls, SIGNAL(valueChanged()), this, SLOT(uiElementChange())); + } + break; + case EFFECT_FIELD_COLOR: + { + ColorButton* cb = new ColorButton(); + ui_element = cb; + connect(cb, SIGNAL(color_changed()), this, SLOT(uiElementChange())); + } + break; + case EFFECT_FIELD_STRING: + { + TextEditEx* edit = new TextEditEx(); + edit->setUndoRedoEnabled(true); + ui_element = edit; + connect(edit, SIGNAL(textChanged()), this, SLOT(uiElementChange())); + } + break; + case EFFECT_FIELD_BOOL: + { + CheckboxEx* cb = new CheckboxEx(); + ui_element = cb; + connect(cb, SIGNAL(clicked(bool)), this, SLOT(uiElementChange())); + connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); + } + break; + case EFFECT_FIELD_COMBO: + { + ComboBoxEx* cb = new ComboBoxEx(); + ui_element = cb; + connect(cb, SIGNAL(activated(int)), this, SLOT(uiElementChange())); + } + break; + case EFFECT_FIELD_FONT: + { + FontCombobox* fcb = new FontCombobox(); + ui_element = fcb; + connect(fcb, SIGNAL(activated(int)), this, SLOT(uiElementChange())); + } + break; + } +} + +QVariant EffectField::get_previous_data() { + switch (type) { + case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->getPreviousValue(); break; + case EFFECT_FIELD_COLOR: return static_cast(ui_element)->getPreviousValue(); break; + case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPreviousValue(); break; + case EFFECT_FIELD_BOOL: return !static_cast(ui_element)->isChecked(); break; + case EFFECT_FIELD_COMBO: return static_cast(ui_element)->getPreviousIndex(); break; + case EFFECT_FIELD_FONT: return static_cast(ui_element)->getPreviousValue(); break; + } + return QVariant(); +} + +QVariant EffectField::get_current_data() { + switch (type) { + case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->value(); break; + case EFFECT_FIELD_COLOR: return static_cast(ui_element)->get_color(); break; + case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPlainTextEx(); break; + case EFFECT_FIELD_BOOL: return static_cast(ui_element)->isChecked(); break; + case EFFECT_FIELD_COMBO: return static_cast(ui_element)->currentIndex(); break; + case EFFECT_FIELD_FONT: return static_cast(ui_element)->currentText(); break; + } + return QVariant(); +} + +double EffectField::frameToTimecode(long frame) { + return ((double) frame / parent_row->parent_effect->parent_clip->sequence->frame_rate); +} + +long EffectField::timecodeToFrame(double timecode) { + return qRound(timecode * parent_row->parent_effect->parent_clip->sequence->frame_rate); +} + +void EffectField::set_current_data(const QVariant& data) { + switch (type) { + case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->set_value(data.toDouble(), false); break; + case EFFECT_FIELD_COLOR: return static_cast(ui_element)->set_color(data.value()); break; + case EFFECT_FIELD_STRING: return static_cast(ui_element)->setPlainTextEx(data.toString()); break; + case EFFECT_FIELD_BOOL: return static_cast(ui_element)->setChecked(data.toBool()); break; + case EFFECT_FIELD_COMBO: return static_cast(ui_element)->setCurrentIndexEx(data.toInt()); break; + case EFFECT_FIELD_FONT: return static_cast(ui_element)->setCurrentTextEx(data.toString()); break; + } +} + +void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { + int before_keyframe_index = -1; + int after_keyframe_index = -1; + long before_keyframe_time = LONG_MIN; + long after_keyframe_time = LONG_MAX; + long frame = timecodeToFrame(timecode); + + for (int i=0;ikeyframe_times.size();i++) { + long eval_keyframe_time = parent_row->keyframe_times.at(i); + if (eval_keyframe_time == frame) { + before = i; + after = i; + return; + } else if (eval_keyframe_time < frame && eval_keyframe_time > before_keyframe_time) { + before_keyframe_index = i; + before_keyframe_time = eval_keyframe_time; + } else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) { + after_keyframe_index = i; + after_keyframe_time = eval_keyframe_time; + } + } + + if ((type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) { + // interpolate + before = before_keyframe_index; + after = after_keyframe_index; + + progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); + + // TODO routines for bezier - currently this is purely linear + } else if (before_keyframe_index > -1) { + before = before_keyframe_index; + after = before_keyframe_index; + } else { + before = after_keyframe_index; + after = after_keyframe_index; + } +} + +bool EffectField::hasKeyframes() { + return (parent_row->isKeyframing() && keyframe_data.size() > 0); +} + +QVariant EffectField::validate_keyframe_data(double timecode, bool async) { + if (hasKeyframes()) { + int before_keyframe; + int after_keyframe; + double progress; + get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); + + int kf_type = (progress < 0.5) ? parent_row->keyframe_types.at(before_keyframe) : parent_row->keyframe_types.at(after_keyframe); + if (kf_type == KEYFRAME_TYPE_SMOOTH) { + double b = 4; + double c = 1.313; + double x = (b * progress) - (b*0.5); + progress = (c*(qPow(M_E, x)/(qPow(M_E, x) + 1)))-((c-1)*0.5); + } + + const QVariant& before_data = keyframe_data.at(before_keyframe); + switch (type) { + case EFFECT_FIELD_DOUBLE: + { + double value; + if (before_keyframe == after_keyframe) { + value = keyframe_data.at(before_keyframe).toDouble(); + } else { + double before_dbl = keyframe_data.at(before_keyframe).toDouble(); + double after_dbl = keyframe_data.at(after_keyframe).toDouble(); + value = double_lerp(before_dbl, after_dbl, progress); + } + if (async) { + return value; + } + static_cast(ui_element)->set_value(value, false); + } + break; + case EFFECT_FIELD_COLOR: + { + QColor value; + if (before_keyframe == after_keyframe) { + value = keyframe_data.at(before_keyframe).value(); + } else { + QColor before_data = keyframe_data.at(before_keyframe).value(); + QColor after_data = keyframe_data.at(after_keyframe).value(); + value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); + } + if (async) { + return value; + } + static_cast(ui_element)->set_color(value); + } + break; + case EFFECT_FIELD_STRING: + if (async) { + return before_data; + } + static_cast(ui_element)->setPlainTextEx(before_data.toString()); + break; + case EFFECT_FIELD_BOOL: + if (async) { + return before_data; + } + static_cast(ui_element)->setChecked(before_data.toBool()); + break; + case EFFECT_FIELD_COMBO: + if (async) { + return before_data; + } + static_cast(ui_element)->setCurrentIndexEx(before_data.toInt()); + break; + case EFFECT_FIELD_FONT: + if (async) { + return before_data; + } + static_cast(ui_element)->setCurrentTextEx(before_data.toString()); + break; + } + } + return QVariant(); +} + +void EffectField::uiElementChange() { + bool enableKeyframes = !(type == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); + if (parent_row->isKeyframing()) { + parent_row->set_keyframe_now(enableKeyframes); + } else if (enableKeyframes) { + // set undo + undo_stack.push(new EffectFieldUndo(this)); + } + emit changed(); +} + +QWidget* EffectField::get_ui_element() { + return ui_element; +} + +void EffectField::set_enabled(bool e) { + ui_element->setEnabled(e); +} + +double EffectField::get_double_value(double timecode, bool async) { + if (async && hasKeyframes()) { + return validate_keyframe_data(timecode, true).toDouble(); + } + validate_keyframe_data(timecode); + return static_cast(ui_element)->value(); +} + +void EffectField::set_double_value(double v) { + static_cast(ui_element)->set_value(v, false); +} + +void EffectField::set_double_default_value(double v) { + static_cast(ui_element)->set_default_value(v); +} + +void EffectField::set_double_minimum_value(double v) { + static_cast(ui_element)->set_minimum_value(v); +} + +void EffectField::set_double_maximum_value(double v) { + static_cast(ui_element)->set_maximum_value(v); +} + +void EffectField::add_combo_item(const QString& name, const QVariant& data) { + static_cast(ui_element)->addItem(name, data); +} + +int EffectField::get_combo_index(double timecode, bool async) { + if (async && hasKeyframes()) { + return validate_keyframe_data(timecode, true).toInt(); + } + validate_keyframe_data(timecode); + return static_cast(ui_element)->currentIndex(); +} + +const QVariant EffectField::get_combo_data(double timecode) { + validate_keyframe_data(timecode); + return static_cast(ui_element)->currentData(); +} + +const QString EffectField::get_combo_string(double timecode) { + validate_keyframe_data(timecode); + return static_cast(ui_element)->currentText(); +} + +void EffectField::set_combo_index(int index) { + static_cast(ui_element)->setCurrentIndexEx(index); +} + +void EffectField::set_combo_string(const QString& s) { + static_cast(ui_element)->setCurrentTextEx(s); +} + +bool EffectField::get_bool_value(double timecode, bool async) { + if (async && hasKeyframes()) { + return validate_keyframe_data(timecode, true).toBool(); + } + validate_keyframe_data(timecode); + return static_cast(ui_element)->isChecked(); +} + +void EffectField::set_bool_value(bool b) { + return static_cast(ui_element)->setChecked(b); +} + +const QString EffectField::get_string_value(double timecode, bool async) { + if (async && hasKeyframes()) { + return validate_keyframe_data(timecode, true).toString(); + } + validate_keyframe_data(timecode); + return static_cast(ui_element)->getPlainTextEx(); +} + +void EffectField::set_string_value(const QString& s) { + static_cast(ui_element)->setPlainTextEx(s); +} + +const QString EffectField::get_font_name(double timecode, bool async) { + if (async && hasKeyframes()) { + return validate_keyframe_data(timecode, true).toString(); + } + validate_keyframe_data(timecode); + return static_cast(ui_element)->currentText(); +} + +void EffectField::set_font_name(const QString& s) { + static_cast(ui_element)->setCurrentText(s); +} + +QColor EffectField::get_color_value(double timecode, bool async) { + if (async && hasKeyframes()) { + return validate_keyframe_data(timecode, true).value(); + } + validate_keyframe_data(timecode); + return static_cast(ui_element)->get_color(); +} + +void EffectField::set_color_value(QColor color) { + static_cast(ui_element)->set_color(color); +} diff --git a/project/effectfield.h b/project/effectfield.h new file mode 100644 index 000000000..7c61ee967 --- /dev/null +++ b/project/effectfield.h @@ -0,0 +1,71 @@ +#ifndef EFFECTFIELD_H +#define EFFECTFIELD_H + +#define EFFECT_FIELD_DOUBLE 0 +#define EFFECT_FIELD_COLOR 1 +#define EFFECT_FIELD_STRING 2 +#define EFFECT_FIELD_BOOL 3 +#define EFFECT_FIELD_COMBO 4 +#define EFFECT_FIELD_FONT 5 + +#include +#include +#include + +class EffectRow; + +class EffectField : public QObject { + Q_OBJECT +public: + EffectField(EffectRow* parent, int t); + EffectRow* parent_row; + int type; + QString id; + + QVariant get_previous_data(); + QVariant get_current_data(); + double frameToTimecode(long frame); + long timecodeToFrame(double timecode); + void set_current_data(const QVariant&); + void get_keyframe_data(double timecode, int& before, int& after, double& d); + QVariant validate_keyframe_data(double timecode, bool async = false); + + double get_double_value(double timecode, bool async = false); + void set_double_value(double v); + void set_double_default_value(double v); + void set_double_minimum_value(double v); + void set_double_maximum_value(double v); + + const QString get_string_value(double timecode, bool async = false); + void set_string_value(const QString &s); + + void add_combo_item(const QString& name, const QVariant &data); + int get_combo_index(double timecode, bool async = false); + const QVariant get_combo_data(double timecode); + const QString get_combo_string(double timecode); + void set_combo_index(int index); + void set_combo_string(const QString& s); + + bool get_bool_value(double timecode, bool async = false); + void set_bool_value(bool b); + + const QString get_font_name(double timecode, bool async = false); + void set_font_name(const QString& s); + + QColor get_color_value(double timecode, bool async = false); + void set_color_value(QColor color); + + QWidget* get_ui_element(); + void set_enabled(bool e); + QVector keyframe_data; + QWidget* ui_element; +private: + bool hasKeyframes(); +private slots: + void uiElementChange(); +signals: + void changed(); + void toggled(bool); +}; + +#endif // EFFECTFIELD_H diff --git a/project/effectrow.cpp b/project/effectrow.cpp new file mode 100644 index 000000000..c4fd58f11 --- /dev/null +++ b/project/effectrow.cpp @@ -0,0 +1,205 @@ +#include "effectrow.h" + +#include +#include +#include +#include + +#include "project/undo.h" +#include "project/clip.h" +#include "project/sequence.h" +#include "panels/panels.h" +#include "panels/effectcontrols.h" +#include "panels/viewer.h" +#include "effect.h" +#include "ui/viewerwidget.h" + +EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, int row) : + parent_effect(parent), + keyframing(false), + ui(uilayout), + name(n), + ui_row(row), + just_made_unsafe_keyframe(false) +{ + label = new QLabel(name); + ui->addWidget(label, row, 0); + + QSize button_size(20, 20); + QSize icon_size(12, 12); + + QHBoxLayout* key_controls = new QHBoxLayout(); + key_controls->setSpacing(0); + key_controls->setMargin(0); + key_controls->addStretch(); + + left_key_nav = new QPushButton("<"); + left_key_nav->setVisible(false); + left_key_nav->setMaximumSize(button_size); + key_controls->addWidget(left_key_nav); + connect(left_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_previous_key())); + + key_addremove = new QPushButton("."); + key_addremove->setVisible(false); + key_addremove->setMaximumSize(button_size); + key_controls->addWidget(key_addremove); + connect(key_addremove, SIGNAL(clicked(bool)), this, SLOT(toggle_key())); + + right_key_nav = new QPushButton(">"); + right_key_nav->setVisible(false); + right_key_nav->setMaximumSize(button_size); + key_controls->addWidget(right_key_nav); + connect(right_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_next_key())); + + keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), ""); + keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); + keyframe_enable->setMaximumSize(button_size); + keyframe_enable->setIconSize(icon_size); + keyframe_enable->setCheckable(true); + keyframe_enable->setToolTip("Enable Keyframes"); + connect(keyframe_enable, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_enabled(bool))); + connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool))); + key_controls->addWidget(keyframe_enable); + + ui->addLayout(key_controls, row, 6); +} + +bool EffectRow::isKeyframing() { + return keyframing; +} + +void EffectRow::setKeyframing(bool b) { + keyframing = b; + keyframe_enable->setChecked(b); +} + +void EffectRow::set_keyframe_enabled(bool enabled) { + if (enabled) { + set_keyframe_now(true); + } else { + if (QMessageBox::question(panel_effect_controls, "Disable Keyframes", "Disabling keyframes will delete all current keyframes. Are you sure you want to do this?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { + // clear + KeyframeDelete* kd = new KeyframeDelete(); + for (int i=keyframe_times.size()-1;i>=0;i--) { + delete_keyframe(kd, i); + } + kd->disable_keyframes_on_row = this; + undo_stack.push(kd); + panel_effect_controls->update_keyframes(); + } else { + setKeyframing(true); + } + } +} + +void EffectRow::keyframe_ui_enabled(bool enabled) { + left_key_nav->setVisible(enabled); + key_addremove->setVisible(enabled); + right_key_nav->setVisible(enabled); +} + +void EffectRow::goto_previous_key() { + long key = LONG_MIN; + Clip* c = parent_effect->parent_clip; + for (int i=0;iclip_in + c->timeline_in; + if (comp < sequence->playhead) { + key = qMax(comp, key); + } + } + if (key != LONG_MIN) panel_sequence_viewer->seek(key); +} + +void EffectRow::toggle_key() { + int index = -1; + Clip* c = parent_effect->parent_clip; + for (int i=0;itimeline_in - c->clip_in + keyframe_times.at(i); + if (comp == sequence->playhead) { + index = i; + break; + } + } + if (index < 0) { + // keyframe doesn't exist, set one + set_keyframe_now(true); + } else { + KeyframeDelete* kd = new KeyframeDelete(); + delete_keyframe(kd, index); + undo_stack.push(kd); + panel_effect_controls->update_keyframes(); + panel_sequence_viewer->viewer_widget->update(); + } +} + +void EffectRow::goto_next_key() { + long key = LONG_MAX; + Clip* c = parent_effect->parent_clip; + for (int i=0;itimeline_in - c->clip_in + keyframe_times.at(i); + if (comp > sequence->playhead) { + key = qMin(comp, key); + } + } + if (key != LONG_MAX) panel_sequence_viewer->seek(key); +} + +EffectField* EffectRow::add_field(int type, int colspan) { + EffectField* field = new EffectField(this, type); + fields.append(field); + QWidget* element = field->get_ui_element(); + ui->addWidget(element, ui_row, fields.size(), 1, colspan); + return field; +} + +EffectRow::~EffectRow() { + for (int i=0;iplayhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in; + for (int i=0;iredo(); + delete ks; + } + + panel_effect_controls->update_keyframes(); +} + +void EffectRow::delete_keyframe_at_time(KeyframeDelete* kd, long time) { + for (int i=0;irows.append(this); + kd->keyframes.append(index); +} + +EffectField* EffectRow::field(int i) { + return fields.at(i); +} + +int EffectRow::fieldCount() { + return fields.size(); +} diff --git a/project/effectrow.h b/project/effectrow.h new file mode 100644 index 000000000..f74940326 --- /dev/null +++ b/project/effectrow.h @@ -0,0 +1,54 @@ +#ifndef EFFECTROW_H +#define EFFECTROW_H + +#include +#include + +class Effect; +class QGridLayout; +class EffectField; +class QLabel; +class KeyframeDelete; +class QPushButton; + +class EffectRow : public QObject { + Q_OBJECT +public: + EffectRow(Effect* parent, QGridLayout* uilayout, const QString& n, int row); + ~EffectRow(); + EffectField* add_field(int type, int colspan = 1); + EffectField* field(int i); + int fieldCount(); + void set_keyframe_now(bool undoable); + void delete_keyframe(KeyframeDelete *kd, int index); + void delete_keyframe_at_time(KeyframeDelete* kd, long time); + QLabel* label; + Effect* parent_effect; + + bool isKeyframing(); + void setKeyframing(bool); + + QVector keyframe_times; + QVector keyframe_types; +private slots: + void set_keyframe_enabled(bool); + void keyframe_ui_enabled(bool); + void goto_previous_key(); + void toggle_key(); + void goto_next_key(); +private: + bool keyframing; + QGridLayout* ui; + QString name; + int ui_row; + QVector fields; + + QPushButton* keyframe_enable; + QPushButton* left_key_nav; + QPushButton* key_addremove; + QPushButton* right_key_nav; + + bool just_made_unsafe_keyframe; +}; + +#endif // EFFECTROW_H diff --git a/project/sequence.cpp b/project/sequence.cpp index 519292280..be887693d 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -1,6 +1,9 @@ #include "sequence.h" -#include "project/clip.h" +#include "clip.h" +#include "transition.h" + +#include "debug.h" Sequence::Sequence() : playhead(0), @@ -51,6 +54,30 @@ long Sequence::getEndFrame() { return end; } +void Sequence::hard_delete_transition(Clip *c, int type) { + int transition_index = (type == TA_OPENING_TRANSITION) ? c->opening_transition : c->closing_transition; + if (transition_index > -1) { + for (int i=0;iopening_transition == transition_index + || cc->closing_transition == transition_index)) { + // another clip is using this, don't delete just yet + return; + } + } + + delete transitions.at(transition_index); + transitions[transition_index] = NULL; + if (type == TA_OPENING_TRANSITION) { + c->opening_transition = -1; + } else { + c->closing_transition = -1; + } + } +} + void Sequence::getTrackLimits(int* video_tracks, int* audio_tracks) { int vt = 0; int at = 0; diff --git a/project/sequence.h b/project/sequence.h index e7caadaab..bd5d20cd6 100644 --- a/project/sequence.h +++ b/project/sequence.h @@ -3,10 +3,12 @@ #include -#include "project/clip.h" #include "project/marker.h" #include "project/selection.h" +struct Clip; +class Transition; + struct Sequence { Sequence(); ~Sequence(); @@ -14,6 +16,7 @@ struct Sequence { QString name; void getTrackLimits(int* video_tracks, int* audio_tracks); long getEndFrame(); + void hard_delete_transition(Clip *c, int type); int width; int height; double frame_rate; @@ -33,6 +36,7 @@ struct Sequence { QVector markers; QVector clips; + QVector transitions; }; // static variable for the currently active sequence diff --git a/project/transition.cpp b/project/transition.cpp new file mode 100644 index 000000000..4ff7f136c --- /dev/null +++ b/project/transition.cpp @@ -0,0 +1,51 @@ +#include "transition.h" + +#include "mainwindow.h" +#include "clip.h" +#include "sequence.h" +#include "debug.h" + +#include "effects/internal/crossdissolvetransition.h" +#include "effects/internal/linearfadetransition.h" +#include "effects/internal/exponentialfadetransition.h" +#include "effects/internal/logarithmicfadetransition.h" + +#include + +Transition::Transition(Clip* c, const EffectMeta* em) : Effect(c, em) { + add_row("Length:")->add_field(EFFECT_FIELD_DOUBLE); +} + +int Transition::copy(Clip *c) { + int copy_index = create_transition(c, meta); + c->sequence->transitions.at(copy_index)->length = length; + return copy_index; +} + +Transition* get_transition_from_meta(Clip* c, const EffectMeta* em) { + if (!em->filename.isEmpty()) { + // load effect from file + return new Transition(c, em); + } else if (em->internal >= 0 && em->internal < TRANSITION_INTERNAL_COUNT) { + // must be an internal effect + switch (em->internal) { + case TRANSITION_INTERNAL_CROSSDISSOLVE: return new CrossDissolveTransition(c, em); + case TRANSITION_INTERNAL_LINEARFADE: return new LinearFadeTransition(c, em); + case TRANSITION_INTERNAL_EXPONENTIALFADE: return new ExponentialFadeTransition(c, em); + case TRANSITION_INTERNAL_LOGARITHMICFADE: return new LogarithmicFadeTransition(c, em); + } + } else { + dout << "[ERROR] Invalid transition data"; + QMessageBox::critical(mainWindow, "Invalid transition", "No candidate for transition '" + em->name + "'. This transition may be corrupt. Try reinstalling it or Olive."); + } + return NULL; +} + +int create_transition(Clip* c, const EffectMeta* em) { + Transition* t = get_transition_from_meta(c, em); + if (t != NULL) { + c->sequence->transitions.append(t); + return c->sequence->transitions.size() - 1; + } + return -1; +} diff --git a/project/transition.h b/project/transition.h new file mode 100644 index 000000000..8b3a69e33 --- /dev/null +++ b/project/transition.h @@ -0,0 +1,24 @@ +#ifndef TRANSITION_H +#define TRANSITION_H + +#include "effect.h" + +#define TA_NO_TRANSITION 0 +#define TA_OPENING_TRANSITION 1 +#define TA_CLOSING_TRANSITION 2 + +#define TRANSITION_INTERNAL_CROSSDISSOLVE 0 +#define TRANSITION_INTERNAL_LINEARFADE 1 +#define TRANSITION_INTERNAL_EXPONENTIALFADE 2 +#define TRANSITION_INTERNAL_LOGARITHMICFADE 3 +#define TRANSITION_INTERNAL_COUNT 4 + +int create_transition(Clip* c, const EffectMeta* em); + +class Transition : public Effect { +public: + Transition(Clip* c, const EffectMeta* em); + int copy(Clip* c); +}; + +#endif // TRANSITION_H diff --git a/project/undo.cpp b/project/undo.cpp index c7aeca279..25ab515de 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -14,6 +14,7 @@ #include "playback/playback.h" #include "ui/sourcetable.h" #include "project/effect.h" +#include "project/transition.h" #include "io/media.h" #include "playback/cacher.h" #include "ui/labelslider.h" @@ -232,23 +233,17 @@ AddTransitionCommand::AddTransitionCommand(Clip* c, const EffectMeta *itransitio {} void AddTransitionCommand::undo() { - if (type == TA_OPENING_TRANSITION) { - delete clip->opening_transition; - clip->opening_transition = NULL; - } else { - delete clip->closing_transition; - clip->closing_transition = NULL; - } + clip->sequence->hard_delete_transition(clip, type); mainWindow->setWindowModified(old_project_changed); } void AddTransitionCommand::redo() { if (type == TA_OPENING_TRANSITION) { - clip->opening_transition = create_effect(clip, transition); - if (length > 0) clip->opening_transition->length = length; + clip->opening_transition = create_transition(clip, transition); + if (length > 0) clip->get_opening_transition()->length = length; } else { - clip->closing_transition = create_effect(clip, transition); - if (length > 0) clip->closing_transition->length = length; + clip->closing_transition = create_transition(clip, transition); + if (length > 0) clip->get_closing_transition()->length = length; } mainWindow->setWindowModified(true); } @@ -261,22 +256,15 @@ ModifyTransitionCommand::ModifyTransitionCommand(Clip* c, int itype, long ilengt {} void ModifyTransitionCommand::undo() { - if (type == TA_OPENING_TRANSITION) { - clip->opening_transition->length = old_length; - } else { - clip->closing_transition->length = old_length; - } + Transition* t = (type == TA_OPENING_TRANSITION) ? clip->get_opening_transition() : clip->get_closing_transition(); + t->length = old_length; mainWindow->setWindowModified(old_project_changed); } void ModifyTransitionCommand::redo() { - if (type == TA_OPENING_TRANSITION) { - old_length = clip->opening_transition->length; - clip->opening_transition->length = new_length; - } else { - old_length = clip->closing_transition->length; - clip->closing_transition->length = new_length; - } + Transition* t = (type == TA_OPENING_TRANSITION) ? clip->get_opening_transition() : clip->get_closing_transition(); + old_length = t->length; + t->length = new_length; mainWindow->setWindowModified(true); } @@ -293,22 +281,19 @@ DeleteTransitionCommand::~DeleteTransitionCommand() { void DeleteTransitionCommand::undo() { if (type == TA_OPENING_TRANSITION) { - clip->opening_transition = transition; + clip->opening_transition = old_index; } else { - clip->closing_transition = transition; + clip->closing_transition = old_index; } + clip->sequence->transitions[old_index] = transition; transition = NULL; mainWindow->setWindowModified(old_project_changed); } void DeleteTransitionCommand::redo() { - if (type == TA_OPENING_TRANSITION) { - transition = clip->opening_transition; - clip->opening_transition = NULL; - } else { - transition = clip->closing_transition; - clip->closing_transition = NULL; - } + old_index = (type == TA_OPENING_TRANSITION) ? clip->opening_transition : clip->closing_transition; + transition = clip->sequence->transitions.at(old_index); + clip->sequence->transitions[old_index] = NULL; mainWindow->setWindowModified(true); } @@ -517,535 +502,6 @@ void AddClipCommand::redo() { mainWindow->setWindowModified(true); } -/* -#define TA_ADD_EFFECT 9 -#define TA_ADD_TRANSITION 10 -#define TA_MODIFY_TRANSITION 11 -#define TA_DELETE_TRANSITION 12 - -TimelineAction::TimelineAction() : - done(false), - change_seq(false), - ripple_enabled(false), - change_in_out(false), - old_project_changed(mainWindow->isWindowModified()) -{} - -TimelineAction::~TimelineAction() { - for (int i=0;idelete_media(deleted_media.at(i)); - delete deleted_media.at(i); - } - } else { - for (int i=0;idelete_media(media_to_add.at(i)); - delete media_to_add.at(i); - } - } -} - -void TimelineAction::offset_links(QVector& clips, int offset) { - for (int i=0;ilinked.size();j++) { - c->linked[j] += offset; - } - } -} - -void TimelineAction::change_sequence(Sequence* s) { - new_seq = s; - change_seq = true; -} - -void TimelineAction::new_sequence(QTreeWidgetItem *s, QTreeWidgetItem* parent) { - new_sequence_items.append(s); - new_sequence_parents.append(parent); -} - -void TimelineAction::add_clips(Sequence* s, QVector& add) { - offset_links(add, clips_to_add.size()); - clips_to_add.append(add); - for (int i=0;iget_clip(clip)->timeline_in, value); -} - -void TimelineAction::set_timeline_out(Sequence* s, int clip, long 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, 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, 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, TA_NO_TRANSITION, 0, value); -} - -void TimelineAction::increase_timeline_out(Sequence* s, int clip, long 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, TA_NO_TRANSITION, 0, value); -} - -void TimelineAction::increase_track(Sequence* s, int clip, int 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, TA_NO_TRANSITION, 0, 0); -} - -void TimelineAction::add_media(QTreeWidgetItem* item, QTreeWidgetItem *parent) { - media_to_add.append(item); - media_to_add_parents.append(parent); -} - -void TimelineAction::delete_media(QTreeWidgetItem* item) { - deleted_media.append(item); -} - -void TimelineAction::ripple(Sequence* s, long point, long length) { - QVector i; - ripple(s, point, length, i); -} - -void TimelineAction::add_effect(Sequence* s, int clip, int 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) { - change_in_out = true; - change_in_out_sequence = s; - - old_in_out_enabled = s->using_workarea; - old_sequence_in = s->workarea_in; - old_sequence_out = s->workarea_out; - - new_in_out_enabled = enabled; - new_sequence_in = in; - new_sequence_out = out; - -} - -void TimelineAction::ripple(Sequence* s, long point, long length, QVector& ignore) { - ripple_enabled = true; - ripple_point = point; - ripple_length = length; - ripple_sequence = s; - ripple_ignores = ignore; -} - -void TimelineAction::undo() { - // re-add deleted media - for (int i=0;isource_table->addTopLevelItem(item); - } else { - parent->addChild(item); - } - } - - // de-ripple clips - if (ripple_enabled) { - for (int i=0;iget_clip(rippled_clips.at(i)); - c->timeline_in -= ripple_length; - c->timeline_out -= ripple_length; - } - } - - for (int i=actions.size()-1;i>=0;i--) { - switch (actions.at(i)) { - case TA_IN: - sequences.at(i)->get_clip(clips.at(i))->timeline_in = old_values.at(i); - break; - case TA_OUT: - sequences.at(i)->get_clip(clips.at(i))->timeline_out = old_values.at(i); - break; - case TA_CLIP_IN: - sequences.at(i)->get_clip(clips.at(i))->clip_in = old_values.at(i); - break; - case TA_TRACK: - sequences.at(i)->get_clip(clips.at(i))->track = old_values.at(i); - break; - case TA_DELETE: - sequences.at(i)->replace_clip(clips.at(i), deleted_clips.at(new_values.at(i))); - break; - case TA_ADD_IN: - sequences.at(i)->get_clip(clips.at(i))->timeline_in -= new_values.at(i); - break; - case TA_ADD_OUT: - sequences.at(i)->get_clip(clips.at(i))->timeline_out -= new_values.at(i); - break; - case TA_ADD_CLIP_IN: - sequences.at(i)->get_clip(clips.at(i))->clip_in -= new_values.at(i); - break; - case TA_ADD_TRACK: - 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; - } - } - - // remove added sequences - for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(new_sequence_items.at(i))); - } else { - new_sequence_parents.at(i)->removeChild(new_sequence_items.at(i)); - } - } - - // restore link references to deleted clips - for (int i=0;iget_clip(removed_link_from.at(i))->linked.append(removed_link_to.at(i)); - } - - // delete added clips - int delete_count = 0; - for (int i=0;idestroy_clip(added_indexes.at(i)-delete_count, true); - delete_count++; - } - - // remove any added media - for (int i=0;isource_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(media_to_add.at(i))); - } else { - media_to_add_parents.at(i)->removeChild(media_to_add.at(i)); - } - } - - // un-change workarea - if (change_in_out) { - change_in_out_sequence->using_workarea = old_in_out_enabled; - change_in_out_sequence->workarea_in = old_sequence_in; - change_in_out_sequence->workarea_out = old_sequence_out; - } - - // un-change current active sequence - if (change_seq) { - set_sequence(old_seq); - } - - mainWindow->setWindowModified(old_project_changed); - - done = false; -} - -void TimelineAction::redo() { - removed_link_from.clear(); - removed_link_to.clear(); - deleted_clips.clear(); - deleted_clips_indices.clear(); - deleted_clip_sequences.clear(); - added_indexes.clear(); - deleted_media_parents.clear(); - removed_link_from_sequence.clear(); - rippled_clips.clear(); - - for (int i=0;isource_table->addTopLevelItem(new_sequence_items.at(i)); - } else { - new_sequence_parents.at(i)->addChild(new_sequence_items.at(i)); - } - } - - // add any new clips - if (clips_to_add.size() > 0) { - QVector copies; - for (int i=0;icopy(sequence_to_add_clips_to.at(i)); - copy->linked.resize(original->linked.size()); - for (int j=0;jlinked.size();j++) { - copy->linked[j] = original->linked.at(j) + sequence_to_add_clips_to.at(i)->clip_count(); - } - copies.append(copy); - } - for (int i=0;iadd_clip(copies.at(i))); - } - } - - for (int i=0;iget_clip(clips.at(i))->timeline_in = new_values.at(i); - } - break; - case TA_OUT: - { - sequences.at(i)->get_clip(clips.at(i))->timeline_out = new_values.at(i); - } - break; - case TA_CLIP_IN: - { - sequences.at(i)->get_clip(clips.at(i))->clip_in = new_values.at(i); - } - break; - case TA_TRACK: - { - sequences.at(i)->get_clip(clips.at(i))->track = new_values.at(i); - } - break; - case TA_DELETE: - { - new_values[i] = deleted_clips.size(); - deleted_clips.append(sequences.at(i)->get_clip(clips.at(i))); - deleted_clips_indices.append(clips.at(i)); - deleted_clip_sequences.append(sequences.at(i)); - sequences.at(i)->replace_clip(clips.at(i), NULL); - } - break; - case TA_ADD_IN: - { - sequences.at(i)->get_clip(clips.at(i))->timeline_in += new_values.at(i); - } - break; - case TA_ADD_OUT: - { - sequences.at(i)->get_clip(clips.at(i))->timeline_out += new_values.at(i); - } - break; - case TA_ADD_CLIP_IN: - { - sequences.at(i)->get_clip(clips.at(i))->clip_in += new_values.at(i); - } - break; - case TA_ADD_TRACK: - { - 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)); - old_values[i] = c->effects.size(); - Effect* e = create_effect(new_values.at(i), c); - c->effects.append(e); - } - 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; - } - } - - // remove any potential link references from deleted clips - for (int i=0;iclip_count();j++) { - Clip* c = s->get_clip(j); - if (c != NULL) { - for (int k=0;klinked.size();k++) { - if (c->linked.at(k) == deleted_clips_indices.at(i)) { - removed_link_from_sequence.append(s); - removed_link_from.append(j); - removed_link_to.append(deleted_clips_indices.at(i)); - c->linked.removeAt(k); - break; - } - } - } - } - } - - // ripple clips - moves all clips after a certain ripple_point by ripple_length - if (ripple_enabled) { - for (int j=0;jclip_count();j++) { - bool found = false; - for (int i=0;iget_clip(j); - if (c != NULL && c->timeline_in >= ripple_point) { - c->timeline_in += ripple_length; - c->timeline_out += ripple_length; - rippled_clips.append(j); - } - } - } - } - - // delete media - for (int i=0;iparent()); - - // if we're deleting the open sequence, close it - if (get_type_from_tree(item) == MEDIA_TYPE_SEQUENCE && - get_sequence_from_tree(item) == sequence && - !change_seq) { - old_seq = sequence; - new_seq = NULL; - change_seq = true; - } - - if (item->parent() == NULL) { - panel_project->source_table->takeTopLevelItem(panel_project->source_table->indexOfTopLevelItem(item)); - } else { - item->parent()->removeChild(item); - } - } - - // add any new media - for (int i=0;isource_table->addTopLevelItem(media_to_add.at(i)); - } else { - media_to_add_parents.at(i)->addChild(media_to_add.at(i)); - } - } - - // change sequence workarea - if (change_in_out) { - change_in_out_sequence->using_workarea = new_in_out_enabled; - change_in_out_sequence->workarea_in = new_sequence_in; - change_in_out_sequence->workarea_out = new_sequence_out; - } - - // change current sequence - if (change_seq) { - old_seq = sequence; - set_sequence(new_seq); - } - - mainWindow->setWindowModified(true); - - done = true; -}*/ - LinkCommand::LinkCommand() : link(true), old_project_changed(mainWindow->isWindowModified()) {} void LinkCommand::undo() { diff --git a/project/undo.h b/project/undo.h index d770a5c4c..80b177176 100644 --- a/project/undo.h +++ b/project/undo.h @@ -22,10 +22,6 @@ struct EffectMeta; #include #include -#define TA_NO_TRANSITION 0 -#define TA_OPENING_TRANSITION 1 -#define TA_CLOSING_TRANSITION 2 - extern QUndoStack undo_stack; class ComboAction : public QUndoCommand { @@ -105,7 +101,7 @@ private: class AddTransitionCommand : public QUndoCommand { public: - AddTransitionCommand(Clip* c, const EffectMeta* itransition, int itype, int ilength); + AddTransitionCommand(Clip* c, const EffectMeta* itransition, int itype, int ilength); void undo(); void redo(); private: @@ -138,7 +134,8 @@ public: private: Clip* clip; int type; - Effect* transition; + Transition* transition; + int old_index; bool old_project_changed; }; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index e502acaf2..e599cf5ab 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -4,6 +4,7 @@ #include "panels/panels.h" #include "io/config.h" #include "project/sequence.h" +#include "project/transition.h" #include "project/clip.h" #include "panels/project.h" #include "panels/timeline.h" @@ -604,11 +605,11 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { Selection s; s.track = clip->track; - if (panel_timeline->transition_select == TA_OPENING_TRANSITION && clip->opening_transition != NULL) { + if (panel_timeline->transition_select == TA_OPENING_TRANSITION && clip->get_opening_transition() != NULL) { s.in = clip->timeline_in; - s.out = clip->timeline_in + clip->opening_transition->length; - } else if (panel_timeline->transition_select == TA_CLOSING_TRANSITION && clip->closing_transition != NULL) { - s.in = clip->timeline_out - clip->closing_transition->length; + s.out = clip->timeline_in + clip->get_opening_transition()->length; + } else if (panel_timeline->transition_select == TA_CLOSING_TRANSITION && clip->get_closing_transition() != NULL) { + s.in = clip->timeline_out - clip->get_closing_transition()->length; s.out = clip->timeline_out; } sequence->selections.append(s); @@ -626,11 +627,11 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { s.out = clip->timeline_out; if (panel_timeline->transition_select == TA_OPENING_TRANSITION) { - s.out = clip->timeline_in + clip->opening_transition->length; + s.out = clip->timeline_in + clip->get_opening_transition()->length; } if (panel_timeline->transition_select == TA_CLOSING_TRANSITION) { - s.in = clip->timeline_out - clip->closing_transition->length; + s.in = clip->timeline_out - clip->get_closing_transition()->length; } s.track = clip->track; @@ -695,24 +696,24 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { void make_room_for_transition(ComboAction* ca, Clip* c, int type, long transition_start, long transition_end) { // make room for transition if (type == TA_OPENING_TRANSITION) { - if (c->opening_transition != NULL) { + if (c->get_opening_transition() != NULL) { ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION)); } - if (c->closing_transition != NULL) { + if (c->get_closing_transition() != NULL) { if (transition_end >= c->timeline_out) { ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION)); - } else if (transition_end > c->timeline_out - c->closing_transition->length) { + } else if (transition_end > c->timeline_out - c->get_closing_transition()->length) { ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, c->timeline_out - transition_end)); } } } else { - if (c->closing_transition != NULL) { + if (c->get_closing_transition() != NULL) { ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION)); } - if (c->opening_transition != NULL) { + if (c->get_opening_transition() != NULL) { if (transition_start <= c->timeline_in) { ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION)); - } else if (transition_start < c->timeline_in + c->opening_transition->length) { + } else if (transition_start < c->timeline_in + c->get_opening_transition()->length) { ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, transition_start - c->timeline_in)); } } @@ -923,30 +924,30 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { // adjust transitions if we need to long new_clip_length = (g.out - g.in); - if (c->opening_transition != NULL) { + if (c->get_opening_transition() != NULL) { long max_open_length = new_clip_length; - if (c->closing_transition != NULL && !panel_timeline->trim_in_point) { - max_open_length -= c->closing_transition->length; + if (c->get_closing_transition() != NULL && !panel_timeline->trim_in_point) { + max_open_length -= c->get_closing_transition()->length; } if (max_open_length <= 0) { ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION)); - } else if (c->opening_transition->length > max_open_length) { + } else if (c->get_opening_transition()->length > max_open_length) { ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, max_open_length)); } } - if (c->closing_transition != NULL) { + if (c->get_closing_transition() != NULL) { long max_open_length = new_clip_length; - if (c->opening_transition != NULL && panel_timeline->trim_in_point) { - max_open_length -= c->opening_transition->length; + if (c->get_opening_transition() != NULL && panel_timeline->trim_in_point) { + max_open_length -= c->get_opening_transition()->length; } if (max_open_length <= 0) { ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION)); - } else if (c->closing_transition->length > max_open_length) { + } else if (c->get_closing_transition()->length > max_open_length) { ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, max_open_length)); } } } else { - bool is_opening_transition = (g.transition == c->opening_transition); + bool is_opening_transition = (g.transition == c->get_opening_transition()); long new_transition_length = g.out - g.in; ca->append(new ModifyTransitionCommand(c, is_opening_transition ? TA_OPENING_TRANSITION : TA_CLOSING_TRANSITION, new_transition_length)); @@ -958,10 +959,10 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { clip_length -= (g.in - g.old_in); } - if (c->closing_transition != NULL) { + if (c->get_closing_transition() != NULL) { if (new_transition_length == clip_length) { ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION)); - } else if (new_transition_length > clip_length - c->closing_transition->length) { + } else if (new_transition_length > clip_length - c->get_closing_transition()->length) { ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, clip_length - new_transition_length)); } } @@ -972,10 +973,10 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { clip_length += (g.out - g.old_out); } - if (c->opening_transition != NULL) { + if (c->get_opening_transition() != NULL) { if (new_transition_length == clip_length) { ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION)); - } else if (new_transition_length > clip_length - c->opening_transition->length) { + } else if (new_transition_length > clip_length - c->get_opening_transition()->length) { ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, clip_length - new_transition_length)); } } @@ -1106,15 +1107,15 @@ void TimelineWidget::init_ghosts() { g.in = g.old_in = c->timeline_in; g.out = g.old_out = c->timeline_out; g.ghost_length = g.old_out - g.old_in; - } else if (g.transition == c->opening_transition) { + } else if (g.transition == c->get_opening_transition()) { g.in = g.old_in = c->timeline_in; - g.out = g.old_out = c->timeline_in + c->opening_transition->length; - g.ghost_length = c->opening_transition->length; - } else if (g.transition == c->closing_transition) { - g.in = g.old_in = c->timeline_out - c->closing_transition->length; + g.out = g.old_out = c->timeline_in + c->get_opening_transition()->length; + g.ghost_length = c->get_opening_transition()->length; + } else if (g.transition == c->get_closing_transition()) { + g.in = g.old_in = c->timeline_out - c->get_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; + g.ghost_length = c->get_closing_transition()->length; + g.clip_in = g.old_clip_in = c->clip_in + c->getLength() - c->get_closing_transition()->length; } // used for trim ops @@ -1354,7 +1355,7 @@ 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 != NULL && g.transition == sequence->clips.at(g.clip)->opening_transition) { + if (g.transition != NULL && g.transition == sequence->clips.at(g.clip)->get_opening_transition()) { g.clip_in = g.old_clip_in + frame_diff; } @@ -1544,21 +1545,21 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { bool add = panel_timeline->is_clip_selected(c, true); // if a whole clip is not selected, maybe just a transition is - if (!add && panel_timeline->tool == TIMELINE_TOOL_POINTER && (c->opening_transition != NULL || c->closing_transition != NULL)) { + if (!add && panel_timeline->tool == TIMELINE_TOOL_POINTER && (c->get_opening_transition() != NULL || c->get_closing_transition() != NULL)) { // check if any selections contain the whole clip or transition for (int j=0;jselections.size();j++) { const Selection& s = sequence->selections.at(j); if (s.track == c->track) { - if (c->opening_transition != NULL + if (c->get_opening_transition() != NULL && s.in == c->timeline_in - && s.out == c->timeline_in + c->opening_transition->length) { - g.transition = c->opening_transition; + && s.out == c->timeline_in + c->get_opening_transition()->length) { + g.transition = c->get_opening_transition(); add = true; break; - } else if (c->closing_transition != NULL - && s.in == c->timeline_out - c->closing_transition->length + } else if (c->get_closing_transition() != NULL + && s.in == c->timeline_out - c->get_closing_transition()->length && s.out == c->timeline_out) { - g.transition = c->closing_transition; + g.transition = c->get_closing_transition(); add = true; break; } @@ -1844,9 +1845,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { tooltip_timer.start(); tooltip_clip = i; - if (c->opening_transition != NULL && panel_timeline->cursor_frame <= c->timeline_in + c->opening_transition->length) { + if (c->get_opening_transition() != NULL && panel_timeline->cursor_frame <= c->timeline_in + c->get_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) { + } else if (c->get_closing_transition() != NULL && panel_timeline->cursor_frame >= c->timeline_out - c->get_closing_transition()->length) { panel_timeline->transition_select = TA_CLOSING_TRANSITION; } } @@ -1869,8 +1870,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } } if (panel_timeline->tool == TIMELINE_TOOL_POINTER) { - if (c->opening_transition != NULL) { - long transition_point = c->timeline_in + c->opening_transition->length; + if (c->get_opening_transition() != NULL) { + long transition_point = c->timeline_in + c->get_opening_transition()->length; if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) { int nc = qAbs(transition_point - 1 - panel_timeline->cursor_frame); @@ -1883,8 +1884,8 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } } } - if (c->closing_transition != NULL) { - long transition_point = c->timeline_out - c->closing_transition->length; + if (c->get_closing_transition() != NULL) { + long transition_point = c->timeline_out - c->get_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) { @@ -2133,13 +2134,13 @@ void TimelineWidget::paintEvent(QPaintEvent*) { int thumb_y = p.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING; if (thumb_x < width() && thumb_y < height()) { int space_for_thumb = clip_rect.width()-1; - if (clip->opening_transition != NULL) { - int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->opening_transition->length); + if (clip->get_opening_transition() != NULL) { + int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->get_opening_transition()->length); thumb_x += ot_width; space_for_thumb -= ot_width; } - if (clip->closing_transition != NULL) { - space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->closing_transition->length); + if (clip->get_closing_transition() != NULL) { + space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->get_closing_transition()->length); } int thumb_height = clip_rect.height()-thumb_y; int thumb_width = (thumb_height*((double)ms->video_preview.width()/(double)ms->video_preview.height())); @@ -2203,7 +2204,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { // draw clip transitions for (int i=0;i<2;i++) { - Effect* t = (i == 0) ? clip->opening_transition : clip->closing_transition; + Transition* t = (i == 0) ? clip->get_opening_transition() : clip->get_closing_transition(); if (t != NULL) { int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->length); int transition_height = clip_rect.height(); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 26cea6ede..30e804dd0 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -5,7 +5,9 @@ #include "panels/timeline.h" #include "panels/project.h" #include "project/sequence.h" +#include "project/clip.h" #include "project/effect.h" +#include "project/transition.h" #include "playback/playback.h" #include "playback/audio.h" #include "io/media.h" @@ -451,18 +453,18 @@ GLuint ViewerWidget::compose_sequence(QVector& nests, bool render_audio) process_effect(c, c->effects.at(j), timecode, coords, composite_texture, fbo_switcher); } - if (c->opening_transition != NULL) { + if (c->get_opening_transition() != NULL) { int transition_progress = playhead - c->timeline_in; - if (transition_progress < c->opening_transition->length) { - process_effect(c, c->opening_transition, (double)transition_progress/(double)c->opening_transition->length, coords, composite_texture, fbo_switcher); + if (transition_progress < c->get_opening_transition()->length) { + process_effect(c, c->get_opening_transition(), (double)transition_progress/(double)c->get_opening_transition()->length, coords, composite_texture, fbo_switcher); //c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length); } } - if (c->closing_transition != NULL) { - int transition_progress = c->closing_transition->length - (playhead - c->timeline_in - c->getLength() + c->closing_transition->length); - if (transition_progress < c->closing_transition->length) { - process_effect(c, c->closing_transition, (double)transition_progress/(double)c->closing_transition->length, coords, composite_texture, fbo_switcher); + if (c->get_closing_transition() != NULL) { + int transition_progress = c->get_closing_transition()->length - (playhead - c->timeline_in - c->getLength() + c->get_closing_transition()->length); + if (transition_progress < c->get_closing_transition()->length) { + process_effect(c, c->get_closing_transition(), (double)transition_progress/(double)c->get_closing_transition()->length, coords, composite_texture, fbo_switcher); //c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length); } }