transition code rewrite for #110

This commit is contained in:
itsmattkc
2018-11-20 22:02:41 +11:00
parent bf0874dbe5
commit e785586df2
35 changed files with 1021 additions and 1378 deletions
+1
View File
@@ -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"
+1
View File
@@ -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"
+1 -1
View File
@@ -2,7 +2,7 @@
#include <QOpenGLFunctions>
CrossDissolveTransition::CrossDissolveTransition(Clip* c, const EffectMeta* em) : Effect(c, em) {
CrossDissolveTransition::CrossDissolveTransition(Clip* c, const EffectMeta* em) : Transition(c, em) {
enable_coords = true;
}
+2 -2
View File
@@ -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 &);
@@ -2,7 +2,7 @@
#include <QtMath>
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;
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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);
@@ -2,7 +2,7 @@
#include <QtMath>
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;
+2 -2
View File
@@ -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);
+2 -2
View File
@@ -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"
+8 -2
View File
@@ -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 \
+3 -2
View File
@@ -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<const EffectMeta*>(q->data().value<quintptr>());
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 {
+1
View File
@@ -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;
+28 -18
View File
@@ -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<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "id") {
@@ -1083,9 +1085,9 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
effect_enabled = (attr.value() == "1");
} else if (attr.name() == "name") {
effect_name = attr.value().toString();
} else if (attr.name() == "length") {
effect_length = attr.value().toInt();
}
} else if (attr.name() == "length") {
effect_length = attr.value().toLong();
}
}
// backwards compatibility with 180820
@@ -1127,18 +1129,26 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
if (meta == NULL) {
dout << "[WARNING] An effect used by this project is missing. It was not loaded.";
} else {
QString tag = stream.name().toString();
QString tag = stream.name().toString();
Effect* e = create_effect(c, meta);
if (effect_length > -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
}
+31 -29
View File
@@ -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;i<sequence->clips.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<Selection>& area
for (int j=0;j<sequence->clips.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<Selection>& 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;
}
}
+2 -1
View File
@@ -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 {
+1
View File
@@ -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"
+9 -8
View File
@@ -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);
}
}
}
+29 -12
View File
@@ -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;i<effects.size();i++) {
delete effects.at(i);
@@ -163,19 +178,21 @@ Clip::~Clip() {
}
long Clip::get_timeline_in_with_transition() {
if (opening_transition != NULL && opening_transition->tlink != 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
+5 -2
View File
@@ -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<Effect*> effects;
QVector<int> 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;
+10 -556
View File
@@ -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 <QCheckBox>
@@ -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;i<rows.size();i++) {
EffectRow* row = rows.at(i);
@@ -762,8 +745,7 @@ void Effect::endEffect() {
Effect* Effect::copy(Clip* c) {
Effect* copy = create_effect(c, meta);
copy->set_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;i<keyframe_times.size();i++) {
long comp = keyframe_times.at(i) - c->clip_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;i<keyframe_times.size();i++) {
long comp = c->timeline_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;i<keyframe_times.size();i++) {
long comp = c->timeline_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;i<fields.size();i++) {
delete fields.at(i);
}
}
void EffectRow::set_keyframe_now(bool undoable) {
int index = -1;
long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
for (int i=0;i<keyframe_times.size();i++) {
if (keyframe_times.at(i) == time) {
index = i;
break;
}
}
KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe);
if (undoable) {
just_made_unsafe_keyframe = false;
undo_stack.push(ks);
} else {
if (index == -1) just_made_unsafe_keyframe = true;
ks->redo();
delete ks;
}
panel_effect_controls->update_keyframes();
}
void EffectRow::delete_keyframe_at_time(KeyframeDelete* kd, long time) {
for (int i=0;i<keyframe_times.size();i++) {
if (keyframe_times.at(i) == time) {
delete_keyframe(kd, i);
break;
}
}
}
void EffectRow::delete_keyframe(KeyframeDelete* kd, int index) {
kd->rows.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<LabelSlider*>(ui_element)->getPreviousValue(); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue(); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue(); break;
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked(); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex(); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue(); break;
}
return QVariant();
}
QVariant EffectField::get_current_data() {
switch (type) {
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value(); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color(); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx(); break;
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked(); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex(); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(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<LabelSlider*>(ui_element)->set_value(data.toDouble(), false); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>()); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString()); break;
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool()); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt()); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(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;i<parent_row->keyframe_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<LabelSlider*>(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<QColor>();
} else {
QColor before_data = keyframe_data.at(before_keyframe).value<QColor>();
QColor after_data = keyframe_data.at(after_keyframe).value<QColor>();
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<ColorButton*>(ui_element)->set_color(value);
}
break;
case EFFECT_FIELD_STRING:
if (async) {
return before_data;
}
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(before_data.toString());
break;
case EFFECT_FIELD_BOOL:
if (async) {
return before_data;
}
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
break;
case EFFECT_FIELD_COMBO:
if (async) {
return before_data;
}
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
break;
case EFFECT_FIELD_FONT:
if (async) {
return before_data;
}
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
break;
}
}
return QVariant();
}
void EffectField::uiElementChange() {
bool enableKeyframes = !(type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(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<LabelSlider*>(ui_element)->value();
}
void EffectField::set_double_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_value(v, false);
}
void EffectField::set_double_default_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_default_value(v);
}
void EffectField::set_double_minimum_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_minimum_value(v);
}
void EffectField::set_double_maximum_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_maximum_value(v);
}
void EffectField::add_combo_item(const QString& name, const QVariant& data) {
static_cast<ComboBoxEx*>(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<ComboBoxEx*>(ui_element)->currentIndex();
}
const QVariant EffectField::get_combo_data(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentData();
}
const QString EffectField::get_combo_string(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentText();
}
void EffectField::set_combo_index(int index) {
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(index);
}
void EffectField::set_combo_string(const QString& s) {
static_cast<ComboBoxEx*>(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<QCheckBox*>(ui_element)->isChecked();
}
void EffectField::set_bool_value(bool b) {
return static_cast<QCheckBox*>(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<TextEditEx*>(ui_element)->getPlainTextEx();
}
void EffectField::set_string_value(const QString& s) {
static_cast<TextEditEx*>(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<FontCombobox*>(ui_element)->currentText();
}
void EffectField::set_font_name(const QString& s) {
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
}
QColor EffectField::get_color_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).value<QColor>();
}
validate_keyframe_data(timecode);
return static_cast<ColorButton*>(ui_element)->get_color();
}
void EffectField::set_color_value(QColor color) {
static_cast<ColorButton*>(ui_element)->set_color(color);
}
qint16 mix_audio_sample(qint16 a, qint16 b) {
qint32 mixed_sample = static_cast<qint32>(a) + static_cast<qint32>(b);
mixed_sample = qMax(qMin(mixed_sample, static_cast<qint32>(INT16_MAX)), static_cast<qint32>(INT16_MIN));
+7 -107
View File
@@ -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<QVariant> 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<long> keyframe_times;
QVector<int> 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<EffectField*> 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();
+352
View File
@@ -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 <QtMath>
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<LabelSlider*>(ui_element)->getPreviousValue(); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue(); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue(); break;
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked(); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex(); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue(); break;
}
return QVariant();
}
QVariant EffectField::get_current_data() {
switch (type) {
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value(); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color(); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx(); break;
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked(); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex(); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(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<LabelSlider*>(ui_element)->set_value(data.toDouble(), false); break;
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>()); break;
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString()); break;
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool()); break;
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt()); break;
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(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;i<parent_row->keyframe_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<LabelSlider*>(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<QColor>();
} else {
QColor before_data = keyframe_data.at(before_keyframe).value<QColor>();
QColor after_data = keyframe_data.at(after_keyframe).value<QColor>();
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<ColorButton*>(ui_element)->set_color(value);
}
break;
case EFFECT_FIELD_STRING:
if (async) {
return before_data;
}
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(before_data.toString());
break;
case EFFECT_FIELD_BOOL:
if (async) {
return before_data;
}
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
break;
case EFFECT_FIELD_COMBO:
if (async) {
return before_data;
}
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
break;
case EFFECT_FIELD_FONT:
if (async) {
return before_data;
}
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
break;
}
}
return QVariant();
}
void EffectField::uiElementChange() {
bool enableKeyframes = !(type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(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<LabelSlider*>(ui_element)->value();
}
void EffectField::set_double_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_value(v, false);
}
void EffectField::set_double_default_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_default_value(v);
}
void EffectField::set_double_minimum_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_minimum_value(v);
}
void EffectField::set_double_maximum_value(double v) {
static_cast<LabelSlider*>(ui_element)->set_maximum_value(v);
}
void EffectField::add_combo_item(const QString& name, const QVariant& data) {
static_cast<ComboBoxEx*>(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<ComboBoxEx*>(ui_element)->currentIndex();
}
const QVariant EffectField::get_combo_data(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentData();
}
const QString EffectField::get_combo_string(double timecode) {
validate_keyframe_data(timecode);
return static_cast<ComboBoxEx*>(ui_element)->currentText();
}
void EffectField::set_combo_index(int index) {
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(index);
}
void EffectField::set_combo_string(const QString& s) {
static_cast<ComboBoxEx*>(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<QCheckBox*>(ui_element)->isChecked();
}
void EffectField::set_bool_value(bool b) {
return static_cast<QCheckBox*>(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<TextEditEx*>(ui_element)->getPlainTextEx();
}
void EffectField::set_string_value(const QString& s) {
static_cast<TextEditEx*>(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<FontCombobox*>(ui_element)->currentText();
}
void EffectField::set_font_name(const QString& s) {
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
}
QColor EffectField::get_color_value(double timecode, bool async) {
if (async && hasKeyframes()) {
return validate_keyframe_data(timecode, true).value<QColor>();
}
validate_keyframe_data(timecode);
return static_cast<ColorButton*>(ui_element)->get_color();
}
void EffectField::set_color_value(QColor color) {
static_cast<ColorButton*>(ui_element)->set_color(color);
}
+71
View File
@@ -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 <QObject>
#include <QVariant>
#include <QVector>
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<QVariant> keyframe_data;
QWidget* ui_element;
private:
bool hasKeyframes();
private slots:
void uiElementChange();
signals:
void changed();
void toggled(bool);
};
#endif // EFFECTFIELD_H
+205
View File
@@ -0,0 +1,205 @@
#include "effectrow.h"
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>
#include <QMessageBox>
#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;i<keyframe_times.size();i++) {
long comp = keyframe_times.at(i) - c->clip_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;i<keyframe_times.size();i++) {
long comp = c->timeline_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;i<keyframe_times.size();i++) {
long comp = c->timeline_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;i<fields.size();i++) {
delete fields.at(i);
}
}
void EffectRow::set_keyframe_now(bool undoable) {
int index = -1;
long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
for (int i=0;i<keyframe_times.size();i++) {
if (keyframe_times.at(i) == time) {
index = i;
break;
}
}
KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe);
if (undoable) {
just_made_unsafe_keyframe = false;
undo_stack.push(ks);
} else {
if (index == -1) just_made_unsafe_keyframe = true;
ks->redo();
delete ks;
}
panel_effect_controls->update_keyframes();
}
void EffectRow::delete_keyframe_at_time(KeyframeDelete* kd, long time) {
for (int i=0;i<keyframe_times.size();i++) {
if (keyframe_times.at(i) == time) {
delete_keyframe(kd, i);
break;
}
}
}
void EffectRow::delete_keyframe(KeyframeDelete* kd, int index) {
kd->rows.append(this);
kd->keyframes.append(index);
}
EffectField* EffectRow::field(int i) {
return fields.at(i);
}
int EffectRow::fieldCount() {
return fields.size();
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef EFFECTROW_H
#define EFFECTROW_H
#include <QObject>
#include <QVector>
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<long> keyframe_times;
QVector<int> 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<EffectField*> fields;
QPushButton* keyframe_enable;
QPushButton* left_key_nav;
QPushButton* key_addremove;
QPushButton* right_key_nav;
bool just_made_unsafe_keyframe;
};
#endif // EFFECTROW_H
+28 -1
View File
@@ -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;i<clips.size();i++) {
Clip* cc = clips.at(i);
if (cc != NULL
&& c != cc
&& (cc->opening_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;
+5 -1
View File
@@ -3,10 +3,12 @@
#include <QVector>
#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<Marker> markers;
QVector<Clip*> clips;
QVector<Transition*> transitions;
};
// static variable for the currently active sequence
+51
View File
@@ -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 <QMessageBox>
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;
}
+24
View File
@@ -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
+17 -561
View File
@@ -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;i<clips_to_add.size();i++) {
delete clips_to_add.at(i);
}
if (done) {
for (int i=0;i<deleted_clips.size();i++) {
delete deleted_clips.at(i);
}
for (int i=0;i<deleted_media.size();i++) {
panel_project->delete_media(deleted_media.at(i));
delete deleted_media.at(i);
}
} else {
for (int i=0;i<new_sequence_items.size();i++) {
delete get_sequence_from_tree(new_sequence_items.at(i));
delete new_sequence_items.at(i);
}
for (int i=0;i<media_to_add.size();i++) {
panel_project->delete_media(media_to_add.at(i));
delete media_to_add.at(i);
}
}
}
void TimelineAction::offset_links(QVector<Clip*>& clips, int offset) {
for (int i=0;i<clips.size();i++) {
Clip* c = clips.at(i);
for (int j=0;j<c->linked.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<Clip*>& add) {
offset_links(add, clips_to_add.size());
clips_to_add.append(add);
for (int i=0;i<clips_to_add.size();i++) {
sequence_to_add_clips_to.append(s);
}
}
void TimelineAction::new_action(Sequence* s, int action, int clip, int transition_type, long old_val, long new_val) {
sequences.append(s);
actions.append(action);
clips.append(clip);
transition_types.append(transition_type);
old_values.append(old_val);
new_values.append(new_val);
}
void TimelineAction::set_timeline_in(Sequence* s, int clip, long value) {
new_action(s, TA_IN, clip, TA_NO_TRANSITION, s->get_clip(clip)->timeline_in, value);
}
void TimelineAction::set_timeline_out(Sequence* s, int clip, long value) {
new_action(s, TA_OUT, clip, 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<int> 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<int>& 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;i<deleted_media.size();i++) {
QTreeWidgetItem* item = deleted_media.at(i);
QTreeWidgetItem* parent = deleted_media_parents.at(i);
if (parent == NULL) {
panel_project->source_table->addTopLevelItem(item);
} else {
parent->addChild(item);
}
}
// de-ripple clips
if (ripple_enabled) {
for (int i=0;i<rippled_clips.size();i++) {
Clip* c = ripple_sequence->get_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;i<new_sequence_items.size();i++) {
if (new_sequence_parents.at(i) == NULL) {
panel_project->source_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;i<removed_link_to.size();i++) {
removed_link_from_sequence.at(i)->get_clip(removed_link_from.at(i))->linked.append(removed_link_to.at(i));
}
// delete added clips
int delete_count = 0;
for (int i=0;i<clips_to_add.size();i++) {
sequence_to_add_clips_to.at(i)->destroy_clip(added_indexes.at(i)-delete_count, true);
delete_count++;
}
// remove any added media
for (int i=0;i<media_to_add.size();i++) {
if (media_to_add_parents.at(i) == NULL) {
panel_project->source_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;i<new_sequence_items.size();i++) {
if (new_sequence_parents.at(i) == NULL) {
panel_project->source_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<Clip*> copies;
for (int i=0;i<clips_to_add.size();i++) {
Clip* original = clips_to_add.at(i);
Clip* copy = original->copy(sequence_to_add_clips_to.at(i));
copy->linked.resize(original->linked.size());
for (int j=0;j<original->linked.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;i<clips_to_add.size();i++) {
added_indexes.append(sequence_to_add_clips_to.at(i)->add_clip(copies.at(i)));
}
}
for (int i=0;i<actions.size();i++) {
switch (actions.at(i)) {
case TA_IN:
{
sequences.at(i)->get_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;i<deleted_clips_indices.size();i++) {
Sequence* s = deleted_clip_sequences.at(i);
for (int j=0;j<s->clip_count();j++) {
Clip* c = s->get_clip(j);
if (c != NULL) {
for (int k=0;k<c->linked.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;j<ripple_sequence->clip_count();j++) {
bool found = false;
for (int i=0;i<ripple_ignores.size();i++) {
if (ripple_ignores.at(i) == j) {
found = true;
break;
}
}
if (!found) {
Clip* c = ripple_sequence->get_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;i<deleted_media.size();i++) {
QTreeWidgetItem* item = deleted_media.at(i);
deleted_media_parents.append(item->parent());
// 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;i<media_to_add.size();i++) {
if (media_to_add_parents.at(i) == NULL) {
panel_project->source_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() {
+3 -6
View File
@@ -22,10 +22,6 @@ struct EffectMeta;
#include <QVector>
#include <QVariant>
#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;
};
+52 -51
View File
@@ -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;j<sequence->selections.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();
+9 -7
View File
@@ -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<Clip*>& 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);
}
}