implemented full bezier interpolation for keyframes
This commit is contained in:
+193
-193
@@ -52,14 +52,14 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
|
||||
switch (em->internal) {
|
||||
case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em);
|
||||
case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em);
|
||||
case EFFECT_INTERNAL_TIMECODE: return new TimecodeEffect(c, em);
|
||||
case EFFECT_INTERNAL_TIMECODE: return new TimecodeEffect(c, em);
|
||||
case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em);
|
||||
case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, 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_CORNERPIN: return new CornerPinEffect(c, em);
|
||||
case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em);
|
||||
case EFFECT_INTERNAL_CORNERPIN: return new CornerPinEffect(c, em);
|
||||
}
|
||||
} else {
|
||||
dout << "[ERROR] Invalid effect data";
|
||||
@@ -69,12 +69,12 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
|
||||
}
|
||||
|
||||
const EffectMeta* get_internal_meta(int internal_id, int type) {
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
if (effects.at(i).internal == internal_id && effects.at(i).type == type) {
|
||||
return &effects.at(i);
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
if (effects.at(i).internal == internal_id && effects.at(i).type == type) {
|
||||
return &effects.at(i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void load_internal_effects() {
|
||||
@@ -82,77 +82,77 @@ void load_internal_effects() {
|
||||
|
||||
// internal effects
|
||||
em.type = EFFECT_TYPE_EFFECT;
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
|
||||
em.name = "Volume";
|
||||
em.internal = EFFECT_INTERNAL_VOLUME;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Pan";
|
||||
em.internal = EFFECT_INTERNAL_PAN;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Tone";
|
||||
em.internal = EFFECT_INTERNAL_TONE;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Noise";
|
||||
em.internal = EFFECT_INTERNAL_NOISE;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
|
||||
em.name = "Transform";
|
||||
em.category = "Distort";
|
||||
em.internal = EFFECT_INTERNAL_TRANSFORM;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Corner Pin";
|
||||
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
||||
effects.append(em);
|
||||
em.name = "Corner Pin";
|
||||
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Mask";
|
||||
em.internal = EFFECT_INTERNAL_MASK;
|
||||
effects.append(em);
|
||||
em.name = "Mask";
|
||||
em.internal = EFFECT_INTERNAL_MASK;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Shake";
|
||||
em.internal = EFFECT_INTERNAL_SHAKE;
|
||||
effects.append(em);
|
||||
em.name = "Shake";
|
||||
em.internal = EFFECT_INTERNAL_SHAKE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Text";
|
||||
em.category = "Render";
|
||||
em.internal = EFFECT_INTERNAL_TEXT;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Timecode";
|
||||
em.internal = EFFECT_INTERNAL_TIMECODE;
|
||||
effects.append(em);
|
||||
em.name = "Timecode";
|
||||
em.internal = EFFECT_INTERNAL_TIMECODE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Solid";
|
||||
em.name = "Solid";
|
||||
em.internal = EFFECT_INTERNAL_SOLID;
|
||||
effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
// internal transitions
|
||||
em.type = EFFECT_TYPE_TRANSITION;
|
||||
em.category = "";
|
||||
|
||||
em.name = "Cross Dissolve";
|
||||
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
|
||||
effects.append(em);
|
||||
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
|
||||
effects.append(em);
|
||||
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
|
||||
em.name = "Linear Fade";
|
||||
em.internal = TRANSITION_INTERNAL_LINEARFADE;
|
||||
effects.append(em);
|
||||
em.internal = TRANSITION_INTERNAL_LINEARFADE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Exponential Fade";
|
||||
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
|
||||
effects.append(em);
|
||||
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Logarithmic Fade";
|
||||
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
|
||||
effects.append(em);
|
||||
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
|
||||
effects.append(em);
|
||||
}
|
||||
|
||||
void load_shader_effects() {
|
||||
@@ -236,29 +236,29 @@ void EffectInit::run() {
|
||||
|
||||
Effect::Effect(Clip* c, const EffectMeta *em) :
|
||||
parent_clip(c),
|
||||
meta(em),
|
||||
meta(em),
|
||||
enable_shader(false),
|
||||
enable_coords(false),
|
||||
enable_superimpose(false),
|
||||
enable_image(false),
|
||||
enable_superimpose(false),
|
||||
enable_image(false),
|
||||
glslProgram(NULL),
|
||||
texture(NULL),
|
||||
isOpen(false),
|
||||
bound(false),
|
||||
enable_always_update(false)
|
||||
texture(NULL),
|
||||
isOpen(false),
|
||||
bound(false),
|
||||
enable_always_update(false)
|
||||
{
|
||||
// set up base UI
|
||||
container = new CollapsibleWidget();
|
||||
connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed()));
|
||||
ui = new QWidget();
|
||||
ui_layout = new QGridLayout();
|
||||
// set up base UI
|
||||
container = new CollapsibleWidget();
|
||||
connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed()));
|
||||
ui = new QWidget();
|
||||
ui_layout = new QGridLayout();
|
||||
ui_layout->setSpacing(4);
|
||||
ui->setLayout(ui_layout);
|
||||
ui->setLayout(ui_layout);
|
||||
container->setContents(ui);
|
||||
|
||||
connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
|
||||
|
||||
// set up UI from effect file
|
||||
// set up UI from effect file
|
||||
container->setText(em->name);
|
||||
|
||||
if (!em->filename.isEmpty()) {
|
||||
@@ -277,7 +277,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
|
||||
}
|
||||
}
|
||||
if (!row_name.isEmpty()) {
|
||||
EffectRow* row = add_row(row_name + ":");
|
||||
EffectRow* row = add_row(row_name);
|
||||
while (!reader.atEnd() && !(reader.name() == "row" && reader.isEndElement())) {
|
||||
reader.readNext();
|
||||
if (reader.name() == "field" && reader.isStartElement()) {
|
||||
@@ -311,7 +311,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
|
||||
if (id.isEmpty()) {
|
||||
dout << "[ERROR] Couldn't load field from" << em->filename << "- ID cannot be empty.";
|
||||
} else if (type > -1) {
|
||||
EffectField* field = row->add_field(type, id);
|
||||
EffectField* field = row->add_field(type, id);
|
||||
connect(field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
@@ -447,27 +447,27 @@ Effect::~Effect() {
|
||||
for (int i=0;i<rows.size();i++) {
|
||||
delete rows.at(i);
|
||||
}
|
||||
for (int i=0;i<gizmos.size();i++) {
|
||||
delete gizmos.at(i);
|
||||
}
|
||||
for (int i=0;i<gizmos.size();i++) {
|
||||
delete gizmos.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Effect::copy_field_keyframes(Effect* e) {
|
||||
for (int i=0;i<rows.size();i++) {
|
||||
EffectRow* row = rows.at(i);
|
||||
EffectRow* copy_row = e->rows.at(i);
|
||||
copy_row->setKeyframing(row->isKeyframing());
|
||||
copy_row->setKeyframing(row->isKeyframing());
|
||||
for (int j=0;j<row->fieldCount();j++) {
|
||||
EffectField* field = row->field(j);
|
||||
EffectField* copy_field = copy_row->field(j);
|
||||
copy_field->keyframes = field->keyframes;
|
||||
EffectField* field = row->field(j);
|
||||
EffectField* copy_field = copy_row->field(j);
|
||||
copy_field->keyframes = field->keyframes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EffectRow* Effect::add_row(const QString& name, bool savable) {
|
||||
EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size());
|
||||
rows.append(row);
|
||||
EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size());
|
||||
rows.append(row);
|
||||
return row;
|
||||
}
|
||||
|
||||
@@ -476,53 +476,53 @@ EffectRow* Effect::row(int i) {
|
||||
}
|
||||
|
||||
int Effect::row_count() {
|
||||
return rows.size();
|
||||
return rows.size();
|
||||
}
|
||||
|
||||
EffectGizmo *Effect::add_gizmo(int type) {
|
||||
EffectGizmo* gizmo = new EffectGizmo(type);
|
||||
gizmos.append(gizmo);
|
||||
return gizmo;
|
||||
EffectGizmo* gizmo = new EffectGizmo(type);
|
||||
gizmos.append(gizmo);
|
||||
return gizmo;
|
||||
}
|
||||
|
||||
EffectGizmo *Effect::gizmo(int i) {
|
||||
return gizmos.at(i);
|
||||
return gizmos.at(i);
|
||||
}
|
||||
|
||||
int Effect::gizmo_count(){
|
||||
return gizmos.size();
|
||||
return gizmos.size();
|
||||
}
|
||||
|
||||
void Effect::refresh() {}
|
||||
|
||||
void Effect::field_changed() {
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
panel_graph_editor->update_panel();
|
||||
}
|
||||
|
||||
void Effect::show_context_menu(const QPoint& pos) {
|
||||
if (meta->type == EFFECT_TYPE_EFFECT) {
|
||||
QMenu menu(mainWindow);
|
||||
if (meta->type == EFFECT_TYPE_EFFECT) {
|
||||
QMenu menu(mainWindow);
|
||||
|
||||
int index = get_index_in_clip();
|
||||
int index = get_index_in_clip();
|
||||
|
||||
if (index > 0) {
|
||||
QAction* move_up = menu.addAction("Move &Up");
|
||||
connect(move_up, SIGNAL(triggered(bool)), this, SLOT(move_up()));
|
||||
}
|
||||
if (index > 0) {
|
||||
QAction* move_up = menu.addAction("Move &Up");
|
||||
connect(move_up, SIGNAL(triggered(bool)), this, SLOT(move_up()));
|
||||
}
|
||||
|
||||
if (index < parent_clip->effects.size() - 1) {
|
||||
QAction* move_down = menu.addAction("Move &Down");
|
||||
connect(move_down, SIGNAL(triggered(bool)), this, SLOT(move_down()));
|
||||
}
|
||||
if (index < parent_clip->effects.size() - 1) {
|
||||
QAction* move_down = menu.addAction("Move &Down");
|
||||
connect(move_down, SIGNAL(triggered(bool)), this, SLOT(move_down()));
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
menu.addSeparator();
|
||||
|
||||
QAction* del_action = menu.addAction("D&elete");
|
||||
connect(del_action, SIGNAL(triggered(bool)), this, SLOT(delete_self()));
|
||||
QAction* del_action = menu.addAction("D&elete");
|
||||
connect(del_action, SIGNAL(triggered(bool)), this, SLOT(delete_self()));
|
||||
|
||||
menu.exec(container->title_bar->mapToGlobal(pos));
|
||||
}
|
||||
menu.exec(container->title_bar->mapToGlobal(pos));
|
||||
}
|
||||
}
|
||||
|
||||
void Effect::delete_self() {
|
||||
@@ -572,24 +572,24 @@ void Effect::set_enabled(bool b) {
|
||||
|
||||
QVariant load_data_from_string(int type, const QString& string) {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return string.toDouble();
|
||||
case EFFECT_FIELD_COLOR: return QColor(string);
|
||||
case EFFECT_FIELD_STRING: return string;
|
||||
case EFFECT_FIELD_BOOL: return (string == "1");
|
||||
case EFFECT_FIELD_COMBO: return string.toInt();
|
||||
case EFFECT_FIELD_FONT: return string;
|
||||
case EFFECT_FIELD_DOUBLE: return string.toDouble();
|
||||
case EFFECT_FIELD_COLOR: return QColor(string);
|
||||
case EFFECT_FIELD_STRING: return string;
|
||||
case EFFECT_FIELD_BOOL: return (string == "1");
|
||||
case EFFECT_FIELD_COMBO: return string.toInt();
|
||||
case EFFECT_FIELD_FONT: return string;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QString save_data_to_string(int type, const QVariant& data) {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble());
|
||||
case EFFECT_FIELD_COLOR: return data.value<QColor>().name();
|
||||
case EFFECT_FIELD_STRING: return data.toString();
|
||||
case EFFECT_FIELD_BOOL: return QString::number(data.toBool());
|
||||
case EFFECT_FIELD_COMBO: return QString::number(data.toInt());
|
||||
case EFFECT_FIELD_FONT: return data.toString();
|
||||
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble());
|
||||
case EFFECT_FIELD_COLOR: return data.value<QColor>().name();
|
||||
case EFFECT_FIELD_STRING: return data.toString();
|
||||
case EFFECT_FIELD_BOOL: return QString::number(data.toBool());
|
||||
case EFFECT_FIELD_COMBO: return QString::number(data.toInt());
|
||||
case EFFECT_FIELD_FONT: return data.toString();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
@@ -610,7 +610,7 @@ void Effect::load(QXmlStreamReader& stream) {
|
||||
stream.readNext();
|
||||
|
||||
// read keyframes
|
||||
/*if (stream.name() == "keyframes" && stream.isStartElement()) {
|
||||
/*if (stream.name() == "keyframes" && stream.isStartElement()) {
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "enabled") {
|
||||
@@ -631,19 +631,19 @@ void Effect::load(QXmlStreamReader& stream) {
|
||||
keyframe_type = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
for (int k=0;k<row->fieldCount();k++) {
|
||||
EffectField* field = row->field(k);
|
||||
EffectKeyframe key;
|
||||
key.time = keyframe_frame;
|
||||
key.type = keyframe_type;
|
||||
field->keyframes.append(key);
|
||||
}
|
||||
for (int k=0;k<row->fieldCount();k++) {
|
||||
EffectField* field = row->field(k);
|
||||
EffectKeyframe key;
|
||||
key.time = keyframe_frame;
|
||||
key.type = keyframe_type;
|
||||
field->keyframes.append(key);
|
||||
}
|
||||
}
|
||||
stream.readNext();
|
||||
}
|
||||
}
|
||||
stream.readNext();
|
||||
}*/
|
||||
}*/
|
||||
|
||||
// read field
|
||||
if (stream.name() == "field" && stream.isStartElement()) {
|
||||
@@ -683,22 +683,22 @@ void Effect::load(QXmlStreamReader& stream) {
|
||||
while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) {
|
||||
stream.readNext();
|
||||
|
||||
// read keyframes
|
||||
// read keyframes
|
||||
if (stream.name() == "key" && stream.isStartElement()) {
|
||||
row->setKeyframing(true);
|
||||
row->setKeyframing(true);
|
||||
|
||||
EffectKeyframe key;
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "value") {
|
||||
key.data = load_data_from_string(field->type, attr.value().toString());
|
||||
} else if (attr.name() == "frame") {
|
||||
key.time = attr.value().toLong();
|
||||
} else if (attr.name() == "type") {
|
||||
key.type = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
field->keyframes.append(key);
|
||||
EffectKeyframe key;
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "value") {
|
||||
key.data = load_data_from_string(field->type, attr.value().toString());
|
||||
} else if (attr.name() == "frame") {
|
||||
key.time = attr.value().toLong();
|
||||
} else if (attr.name() == "type") {
|
||||
key.type = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
field->keyframes.append(key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -718,29 +718,29 @@ void Effect::load(QXmlStreamReader& stream) {
|
||||
|
||||
void Effect::save(QXmlStreamWriter& stream) {
|
||||
stream.writeAttribute("name", meta->name);
|
||||
stream.writeAttribute("enabled", QString::number(is_enabled()));
|
||||
stream.writeAttribute("enabled", QString::number(is_enabled()));
|
||||
|
||||
for (int i=0;i<rows.size();i++) {
|
||||
EffectRow* row = rows.at(i);
|
||||
if (row->savable) {
|
||||
stream.writeStartElement("row"); // row
|
||||
for (int j=0;j<row->fieldCount();j++) {
|
||||
EffectField* field = row->field(j);
|
||||
stream.writeStartElement("field"); // field
|
||||
stream.writeAttribute("id", field->id);
|
||||
stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data()));
|
||||
for (int k=0;k<field->keyframes.size();k++) {
|
||||
const EffectKeyframe& key = field->keyframes.at(k);
|
||||
stream.writeStartElement("key");
|
||||
stream.writeAttribute("value", save_data_to_string(field->type, key.data));
|
||||
stream.writeAttribute("frame", QString::number(key.time));
|
||||
stream.writeAttribute("type", QString::number(key.type));
|
||||
stream.writeEndElement(); // key
|
||||
}
|
||||
stream.writeEndElement(); // field
|
||||
}
|
||||
stream.writeEndElement(); // row
|
||||
}
|
||||
if (row->savable) {
|
||||
stream.writeStartElement("row"); // row
|
||||
for (int j=0;j<row->fieldCount();j++) {
|
||||
EffectField* field = row->field(j);
|
||||
stream.writeStartElement("field"); // field
|
||||
stream.writeAttribute("id", field->id);
|
||||
stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data()));
|
||||
for (int k=0;k<field->keyframes.size();k++) {
|
||||
const EffectKeyframe& key = field->keyframes.at(k);
|
||||
stream.writeStartElement("key");
|
||||
stream.writeAttribute("value", save_data_to_string(field->type, key.data));
|
||||
stream.writeAttribute("frame", QString::number(key.time));
|
||||
stream.writeAttribute("type", QString::number(key.type));
|
||||
stream.writeEndElement(); // key
|
||||
}
|
||||
stream.writeEndElement(); // field
|
||||
}
|
||||
stream.writeEndElement(); // row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,16 +790,16 @@ void Effect::startEffect() {
|
||||
|
||||
void Effect::endEffect() {
|
||||
if (bound) glslProgram->release();
|
||||
bound = false;
|
||||
bound = false;
|
||||
}
|
||||
|
||||
void Effect::process_image(double, uint8_t *, int) {}
|
||||
|
||||
Effect* Effect::copy(Clip* c) {
|
||||
Effect* copy = create_effect(c, meta);
|
||||
copy->set_enabled(is_enabled());
|
||||
copy_field_keyframes(copy);
|
||||
return copy;
|
||||
copy->set_enabled(is_enabled());
|
||||
copy_field_keyframes(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
void Effect::process_shader(double timecode, GLTextureCoords&) {
|
||||
@@ -844,7 +844,7 @@ GLuint Effect::process_superimpose(double timecode) {
|
||||
recreate_texture = true;
|
||||
}
|
||||
|
||||
if (valueHasChanged(timecode) || recreate_texture || enable_always_update) {
|
||||
if (valueHasChanged(timecode) || recreate_texture || enable_always_update) {
|
||||
redraw(timecode);
|
||||
}
|
||||
|
||||
@@ -865,78 +865,78 @@ GLuint Effect::process_superimpose(double timecode) {
|
||||
void Effect::process_audio(double, double, quint8*, int, int) {
|
||||
// only volume/pan, hand off to AU and VST for all other cases
|
||||
|
||||
/*double interval = (timecode_end-timecode_start)/nb_bytes;
|
||||
/*double interval = (timecode_end-timecode_start)/nb_bytes;
|
||||
|
||||
for (int i=0;i<nb_bytes;i+=2) {
|
||||
qint32 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
|
||||
|
||||
jsEngine.globalObject().setProperty("sample", samp);
|
||||
jsEngine.globalObject().setProperty("sample", samp);
|
||||
jsEngine.globalObject().setProperty("volume", row(0)->field(0)->get_double_value(timecode_start+(interval*i), true));
|
||||
QJSValue result = eval.call();
|
||||
samp = result.toInt();
|
||||
QJSValueList args;
|
||||
args << samples << nb_bytes;
|
||||
samp = result.toInt();
|
||||
QJSValueList args;
|
||||
args << samples << nb_bytes;
|
||||
|
||||
|
||||
samples[i+1] = (quint8) (samp >> 8);
|
||||
samples[i] = (quint8) samp;
|
||||
}*/
|
||||
}*/
|
||||
}
|
||||
|
||||
void Effect::gizmo_draw(double, GLTextureCoords &) {}
|
||||
|
||||
void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) {
|
||||
for (int i=0;i<gizmos.size();i++) {
|
||||
if (gizmos.at(i) == gizmo) {
|
||||
ComboAction* ca = NULL;
|
||||
if (done) ca = new ComboAction();
|
||||
if (gizmo->x_field1 != NULL) {
|
||||
gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1);
|
||||
gizmo->x_field1->make_key_from_change(ca);
|
||||
}
|
||||
if (gizmo->y_field1 != NULL) {
|
||||
gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1);
|
||||
gizmo->y_field1->make_key_from_change(ca);
|
||||
}
|
||||
if (gizmo->x_field2 != NULL) {
|
||||
gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2);
|
||||
gizmo->x_field2->make_key_from_change(ca);
|
||||
}
|
||||
if (gizmo->y_field2 != NULL) {
|
||||
gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2);
|
||||
gizmo->y_field2->make_key_from_change(ca);
|
||||
}
|
||||
if (done) undo_stack.push(ca);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<gizmos.size();i++) {
|
||||
if (gizmos.at(i) == gizmo) {
|
||||
ComboAction* ca = NULL;
|
||||
if (done) ca = new ComboAction();
|
||||
if (gizmo->x_field1 != NULL) {
|
||||
gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1);
|
||||
gizmo->x_field1->make_key_from_change(ca);
|
||||
}
|
||||
if (gizmo->y_field1 != NULL) {
|
||||
gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1);
|
||||
gizmo->y_field1->make_key_from_change(ca);
|
||||
}
|
||||
if (gizmo->x_field2 != NULL) {
|
||||
gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2);
|
||||
gizmo->x_field2->make_key_from_change(ca);
|
||||
}
|
||||
if (gizmo->y_field2 != NULL) {
|
||||
gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2);
|
||||
gizmo->y_field2->make_key_from_change(ca);
|
||||
}
|
||||
if (done) undo_stack.push(ca);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Effect::gizmo_world_to_screen() {
|
||||
GLfloat view_val[16];
|
||||
GLfloat projection_val[16];
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, view_val);
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, projection_val);
|
||||
GLfloat view_val[16];
|
||||
GLfloat projection_val[16];
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, view_val);
|
||||
glGetFloatv(GL_PROJECTION_MATRIX, projection_val);
|
||||
|
||||
QMatrix4x4 view_matrix(view_val);
|
||||
QMatrix4x4 projection_matrix(projection_val);
|
||||
QMatrix4x4 view_matrix(view_val);
|
||||
QMatrix4x4 projection_matrix(projection_val);
|
||||
|
||||
for (int i=0;i<gizmos.size();i++) {
|
||||
EffectGizmo* g = gizmos.at(i);
|
||||
for (int i=0;i<gizmos.size();i++) {
|
||||
EffectGizmo* g = gizmos.at(i);
|
||||
|
||||
for (int j=0;j<g->get_point_count();j++) {
|
||||
QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix);
|
||||
for (int j=0;j<g->get_point_count();j++) {
|
||||
QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix);
|
||||
|
||||
int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width);
|
||||
int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height);
|
||||
int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width);
|
||||
int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height);
|
||||
|
||||
g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1);
|
||||
}
|
||||
}
|
||||
g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Effect::are_gizmos_enabled() {
|
||||
return (gizmos.size() > 0);
|
||||
return (gizmos.size() > 0);
|
||||
}
|
||||
|
||||
void Effect::redraw(double) {
|
||||
|
||||
+261
-248
@@ -15,353 +15,366 @@
|
||||
#include "project/sequence.h"
|
||||
|
||||
#include "io/math.h"
|
||||
#include <QtMath>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
EffectField::EffectField(EffectRow *parent, int t, const QString &i) :
|
||||
parent_row(parent),
|
||||
type(t),
|
||||
id(i)
|
||||
parent_row(parent),
|
||||
type(t),
|
||||
id(i)
|
||||
{
|
||||
switch (t) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
{
|
||||
LabelSlider* ls = new LabelSlider();
|
||||
ui_element = ls;
|
||||
connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change()));
|
||||
switch (t) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
{
|
||||
LabelSlider* ls = new LabelSlider();
|
||||
ui_element = ls;
|
||||
connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change()));
|
||||
connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_COLOR:
|
||||
{
|
||||
ColorButton* cb = new ColorButton();
|
||||
ui_element = cb;
|
||||
connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_STRING:
|
||||
{
|
||||
TextEditEx* edit = new TextEditEx();
|
||||
edit->setUndoRedoEnabled(true);
|
||||
ui_element = edit;
|
||||
connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_BOOL:
|
||||
{
|
||||
CheckboxEx* cb = new CheckboxEx();
|
||||
ui_element = cb;
|
||||
connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change()));
|
||||
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(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_FONT:
|
||||
{
|
||||
FontCombobox* fcb = new FontCombobox();
|
||||
ui_element = fcb;
|
||||
connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_COLOR:
|
||||
{
|
||||
ColorButton* cb = new ColorButton();
|
||||
ui_element = cb;
|
||||
connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_STRING:
|
||||
{
|
||||
TextEditEx* edit = new TextEditEx();
|
||||
edit->setUndoRedoEnabled(true);
|
||||
ui_element = edit;
|
||||
connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_BOOL:
|
||||
{
|
||||
CheckboxEx* cb = new CheckboxEx();
|
||||
ui_element = cb;
|
||||
connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change()));
|
||||
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(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_FONT:
|
||||
{
|
||||
FontCombobox* fcb = new FontCombobox();
|
||||
ui_element = fcb;
|
||||
connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QVariant EffectField::get_previous_data() {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->getPreviousValue();
|
||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue();
|
||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue();
|
||||
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex();
|
||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue();
|
||||
}
|
||||
return QVariant();
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->getPreviousValue();
|
||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue();
|
||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue();
|
||||
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex();
|
||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant EffectField::get_current_data() {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value();
|
||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color();
|
||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
|
||||
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
|
||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText();
|
||||
}
|
||||
return QVariant();
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value();
|
||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color();
|
||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
|
||||
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
|
||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
double EffectField::frameToTimecode(long frame) {
|
||||
return ((double) frame / parent_row->parent_effect->parent_clip->sequence->frame_rate);
|
||||
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);
|
||||
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);
|
||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>());
|
||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString());
|
||||
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool());
|
||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt());
|
||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(data.toString());
|
||||
}
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->set_value(data.toDouble(), false);
|
||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>());
|
||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString());
|
||||
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool());
|
||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt());
|
||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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<keyframes.size();i++) {
|
||||
long eval_keyframe_time = keyframes.at(i).time;
|
||||
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;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<keyframes.size();i++) {
|
||||
long eval_keyframe_time = keyframes.at(i).time;
|
||||
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;
|
||||
|
||||
if (keyframes.at(before).type == KEYFRAME_TYPE_HOLD) {
|
||||
progress = 0;
|
||||
} else {
|
||||
// TODO replace with bezier function
|
||||
progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time));
|
||||
}
|
||||
} else if (before_keyframe_index > -1) {
|
||||
before = before_keyframe_index;
|
||||
after = before_keyframe_index;
|
||||
} else {
|
||||
before = after_keyframe_index;
|
||||
after = after_keyframe_index;
|
||||
}
|
||||
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));
|
||||
} 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() && keyframes.size() > 0);
|
||||
return (parent_row->isKeyframing() && keyframes.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);
|
||||
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_BEZIER) {
|
||||
double x = (8.0 * progress) - 4.0;
|
||||
progress = 1.0 / (1.0 + qPow(M_E, -x));
|
||||
progress *= 1.0373;
|
||||
progress -= 0.01865;
|
||||
}*/
|
||||
const QVariant& before_data = keyframes.at(before_keyframe).data;
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
{
|
||||
double value;
|
||||
if (before_keyframe == after_keyframe) {
|
||||
value = keyframes.at(before_keyframe).data.toDouble();
|
||||
} else {
|
||||
const EffectKeyframe& before_key = keyframes.at(before_keyframe);
|
||||
const EffectKeyframe& after_key = keyframes.at(after_keyframe);
|
||||
|
||||
const QVariant& before_data = keyframes.at(before_keyframe).data;
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
{
|
||||
double value;
|
||||
if (before_keyframe == after_keyframe) {
|
||||
value = keyframes.at(before_keyframe).data.toDouble();
|
||||
} else {
|
||||
double before_dbl = keyframes.at(before_keyframe).data.toDouble();
|
||||
double after_dbl = keyframes.at(after_keyframe).data.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 = keyframes.at(before_keyframe).data.value<QColor>();
|
||||
} else {
|
||||
QColor before_data = keyframes.at(before_keyframe).data.value<QColor>();
|
||||
QColor after_data = keyframes.at(after_keyframe).data.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();
|
||||
double before_dbl = before_key.data.toDouble();
|
||||
double after_dbl = after_key.data.toDouble();
|
||||
|
||||
if (before_key.type == KEYFRAME_TYPE_HOLD) {
|
||||
// hold
|
||||
value = before_dbl;
|
||||
} else if (before_key.type == KEYFRAME_TYPE_BEZIER || after_key.type == KEYFRAME_TYPE_BEZIER) {
|
||||
// bezier interpolation
|
||||
if (before_key.type == KEYFRAME_TYPE_BEZIER && after_key.type == KEYFRAME_TYPE_BEZIER) {
|
||||
// cubic bezier
|
||||
double t = cubic_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+before_key.post_handle_x, after_key.time+after_key.pre_handle_x, after_key.time);
|
||||
value = cubic_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl+after_key.pre_handle_y, after_dbl, t);
|
||||
} else if (after_key.type == KEYFRAME_TYPE_LINEAR) { // quadratic bezier
|
||||
// last keyframe is the bezier one
|
||||
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+before_key.post_handle_x, after_key.time);
|
||||
value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t);
|
||||
} else {
|
||||
// this keyframe is the bezier one
|
||||
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+after_key.pre_handle_x, after_key.time);
|
||||
value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t);
|
||||
}
|
||||
} else {
|
||||
// linear
|
||||
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 = keyframes.at(before_keyframe).data.value<QColor>();
|
||||
} else {
|
||||
QColor before_data = keyframes.at(before_keyframe).data.value<QColor>();
|
||||
QColor after_data = keyframes.at(after_keyframe).data.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::ui_element_change() {
|
||||
bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(ui_element)->is_dragging());
|
||||
ComboAction* ca = NULL;
|
||||
if (!dragging_double) ca = new ComboAction();
|
||||
make_key_from_change(ca);
|
||||
if (!dragging_double) undo_stack.push(ca);
|
||||
emit changed();
|
||||
bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(ui_element)->is_dragging());
|
||||
ComboAction* ca = NULL;
|
||||
if (!dragging_double) ca = new ComboAction();
|
||||
make_key_from_change(ca);
|
||||
if (!dragging_double) undo_stack.push(ca);
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void EffectField::make_key_from_change(ComboAction* ca) {
|
||||
if (parent_row->isKeyframing()) {
|
||||
parent_row->set_keyframe_now(ca);
|
||||
} else if (ca != NULL) {
|
||||
// set undo
|
||||
ca->append(new EffectFieldUndo(this));
|
||||
}
|
||||
if (parent_row->isKeyframing()) {
|
||||
parent_row->set_keyframe_now(ca);
|
||||
} else if (ca != NULL) {
|
||||
// set undo
|
||||
ca->append(new EffectFieldUndo(this));
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* EffectField::get_ui_element() {
|
||||
return ui_element;
|
||||
return ui_element;
|
||||
}
|
||||
|
||||
void EffectField::set_enabled(bool e) {
|
||||
ui_element->setEnabled(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();
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
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);
|
||||
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(index);
|
||||
}
|
||||
|
||||
void EffectField::set_combo_string(const QString& s) {
|
||||
static_cast<ComboBoxEx*>(ui_element)->setCurrentTextEx(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();
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
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();
|
||||
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);
|
||||
static_cast<ColorButton*>(ui_element)->set_color(color);
|
||||
}
|
||||
|
||||
+2
-11
@@ -12,20 +12,11 @@
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include "keyframe.h"
|
||||
|
||||
class EffectRow;
|
||||
class ComboAction;
|
||||
|
||||
class EffectKeyframe {
|
||||
public:
|
||||
long time;
|
||||
int type;
|
||||
QVariant data;
|
||||
|
||||
// only for bezier type
|
||||
QPointF pre_handle;
|
||||
QPointF post_handle;
|
||||
};
|
||||
|
||||
class EffectField : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
+132
-132
@@ -17,123 +17,123 @@
|
||||
#include "ui/clickablelabel.h"
|
||||
|
||||
EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row) :
|
||||
parent_effect(parent),
|
||||
savable(save),
|
||||
keyframing(false),
|
||||
ui(uilayout),
|
||||
name(n),
|
||||
ui_row(row),
|
||||
just_made_unsafe_keyframe(false)
|
||||
parent_effect(parent),
|
||||
savable(save),
|
||||
keyframing(false),
|
||||
ui(uilayout),
|
||||
name(n),
|
||||
ui_row(row),
|
||||
just_made_unsafe_keyframe(false)
|
||||
{
|
||||
label = new ClickableLabel(name);
|
||||
label = new ClickableLabel(name + ":");
|
||||
|
||||
ui->addWidget(label, row, 0);
|
||||
ui->addWidget(label, row, 0);
|
||||
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
connect(label, SIGNAL(clicked()), this, SLOT(focus_row()));
|
||||
|
||||
keyframe_nav = new KeyframeNavigator();
|
||||
connect(keyframe_nav, SIGNAL(goto_previous_key()), this, SLOT(goto_previous_key()));
|
||||
connect(keyframe_nav, SIGNAL(toggle_key()), this, SLOT(toggle_key()));
|
||||
connect(keyframe_nav, SIGNAL(goto_next_key()), this, SLOT(goto_next_key()));
|
||||
keyframe_nav = new KeyframeNavigator();
|
||||
connect(keyframe_nav, SIGNAL(goto_previous_key()), this, SLOT(goto_previous_key()));
|
||||
connect(keyframe_nav, SIGNAL(toggle_key()), this, SLOT(toggle_key()));
|
||||
connect(keyframe_nav, SIGNAL(goto_next_key()), this, SLOT(goto_next_key()));
|
||||
connect(keyframe_nav, SIGNAL(keyframe_enabled_changed(bool)), this, SLOT(set_keyframe_enabled(bool)));
|
||||
connect(keyframe_nav, SIGNAL(clicked()), this, SLOT(focus_row()));
|
||||
ui->addWidget(keyframe_nav, row, 6);
|
||||
}
|
||||
ui->addWidget(keyframe_nav, row, 6);
|
||||
}
|
||||
}
|
||||
|
||||
bool EffectRow::isKeyframing() {
|
||||
return keyframing;
|
||||
return keyframing;
|
||||
}
|
||||
|
||||
void EffectRow::setKeyframing(bool b) {
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
keyframing = b;
|
||||
keyframe_nav->enable_keyframes(b);
|
||||
}
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
keyframing = b;
|
||||
keyframe_nav->enable_keyframes(b);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectRow::set_keyframe_enabled(bool enabled) {
|
||||
if (enabled) {
|
||||
ComboAction* ca = new ComboAction();
|
||||
set_keyframe_now(ca);
|
||||
undo_stack.push(ca);
|
||||
} 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
|
||||
ComboAction* ca = new ComboAction();
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
ca->append(new KeyframeDelete(f, 0));
|
||||
}
|
||||
}
|
||||
undo_stack.push(ca);
|
||||
panel_effect_controls->update_keyframes();
|
||||
} else {
|
||||
setKeyframing(true);
|
||||
}
|
||||
}
|
||||
if (enabled) {
|
||||
ComboAction* ca = new ComboAction();
|
||||
set_keyframe_now(ca);
|
||||
undo_stack.push(ca);
|
||||
} 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
|
||||
ComboAction* ca = new ComboAction();
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
ca->append(new KeyframeDelete(f, 0));
|
||||
}
|
||||
}
|
||||
undo_stack.push(ca);
|
||||
panel_effect_controls->update_keyframes();
|
||||
} else {
|
||||
setKeyframing(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EffectRow::goto_previous_key() {
|
||||
long key = LONG_MIN;
|
||||
Clip* c = parent_effect->parent_clip;
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(i).time - c->clip_in + c->timeline_in;
|
||||
if (comp < sequence->playhead) {
|
||||
key = qMax(comp, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key != LONG_MIN) panel_sequence_viewer->seek(key);
|
||||
long key = LONG_MIN;
|
||||
Clip* c = parent_effect->parent_clip;
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(j).time - 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() {
|
||||
QVector<EffectField*> key_fields;
|
||||
QVector<int> key_field_index;
|
||||
Clip* c = parent_effect->parent_clip;
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
long comp = c->timeline_in - c->clip_in + f->keyframes.at(i).time;
|
||||
if (comp == sequence->playhead) {
|
||||
key_fields.append(f);
|
||||
key_field_index.append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
QVector<EffectField*> key_fields;
|
||||
QVector<int> key_field_index;
|
||||
Clip* c = parent_effect->parent_clip;
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
long comp = c->timeline_in - c->clip_in + f->keyframes.at(i).time;
|
||||
if (comp == sequence->playhead) {
|
||||
key_fields.append(f);
|
||||
key_field_index.append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
if (key_fields.size() == 0) {
|
||||
// keyframe doesn't exist, set one
|
||||
set_keyframe_now(ca);
|
||||
} else {
|
||||
for (int i=0;i<key_fields.size();i++) {
|
||||
// TODO: these values must be sorted to work correctly
|
||||
ca->append(new KeyframeDelete(key_fields.at(i), key_field_index.at(i)));
|
||||
}
|
||||
}
|
||||
undo_stack.push(ca);
|
||||
panel_effect_controls->update_keyframes();
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
ComboAction* ca = new ComboAction();
|
||||
if (key_fields.size() == 0) {
|
||||
// keyframe doesn't exist, set one
|
||||
set_keyframe_now(ca);
|
||||
} else {
|
||||
for (int i=0;i<key_fields.size();i++) {
|
||||
// TODO: these values must be sorted to work correctly
|
||||
ca->append(new KeyframeDelete(key_fields.at(i), key_field_index.at(i)));
|
||||
}
|
||||
}
|
||||
undo_stack.push(ca);
|
||||
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<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(i).time - c->clip_in + c->timeline_in;
|
||||
if (comp > sequence->playhead) {
|
||||
key = qMin(comp, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key != LONG_MAX) panel_sequence_viewer->seek(key);
|
||||
long key = LONG_MAX;
|
||||
Clip* c = parent_effect->parent_clip;
|
||||
for (int i=0;i<fieldCount();i++) {
|
||||
EffectField* f = field(i);
|
||||
for (int j=0;j<f->keyframes.size();j++) {
|
||||
long comp = f->keyframes.at(j).time - c->clip_in + c->timeline_in;
|
||||
if (comp > sequence->playhead) {
|
||||
key = qMin(comp, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key != LONG_MAX) panel_sequence_viewer->seek(key);
|
||||
}
|
||||
|
||||
void EffectRow::focus_row() {
|
||||
@@ -141,58 +141,58 @@ void EffectRow::focus_row() {
|
||||
}
|
||||
|
||||
EffectField* EffectRow::add_field(int type, const QString& id, int colspan) {
|
||||
EffectField* field = new EffectField(this, type, id);
|
||||
EffectField* field = new EffectField(this, type, id);
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row()));
|
||||
fields.append(field);
|
||||
QWidget* element = field->get_ui_element();
|
||||
ui->addWidget(element, ui_row, fields.size(), 1, colspan);
|
||||
connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed()));
|
||||
return field;
|
||||
fields.append(field);
|
||||
QWidget* element = field->get_ui_element();
|
||||
ui->addWidget(element, ui_row, fields.size(), 1, colspan);
|
||||
connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed()));
|
||||
return field;
|
||||
}
|
||||
|
||||
EffectRow::~EffectRow() {
|
||||
for (int i=0;i<fields.size();i++) {
|
||||
delete fields.at(i);
|
||||
}
|
||||
for (int i=0;i<fields.size();i++) {
|
||||
delete fields.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectRow::set_keyframe_now(ComboAction* ca) {
|
||||
int index = -1;
|
||||
long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
if (f->keyframes.at(i).time == time) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int index = -1;
|
||||
long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
if (f->keyframes.at(i).time == time) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe);
|
||||
KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe);
|
||||
|
||||
if (ca != NULL) {
|
||||
just_made_unsafe_keyframe = false;
|
||||
ca->append(ks);
|
||||
} else {
|
||||
if (index == -1) just_made_unsafe_keyframe = true;
|
||||
ks->redo();
|
||||
delete ks;
|
||||
}
|
||||
if (ca != NULL) {
|
||||
just_made_unsafe_keyframe = false;
|
||||
ca->append(ks);
|
||||
} else {
|
||||
if (index == -1) just_made_unsafe_keyframe = true;
|
||||
ks->redo();
|
||||
delete ks;
|
||||
}
|
||||
|
||||
panel_effect_controls->update_keyframes();
|
||||
panel_effect_controls->update_keyframes();
|
||||
}
|
||||
|
||||
void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) {
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
if (f->keyframes.at(i).time == time) {
|
||||
ca->append(new KeyframeDelete(f, i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j=0;j<fieldCount();j++) {
|
||||
EffectField* f = field(j);
|
||||
for (int i=0;i<f->keyframes.size();i++) {
|
||||
if (f->keyframes.at(i).time == time) {
|
||||
ca->append(new KeyframeDelete(f, i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QString &EffectRow::get_name() {
|
||||
@@ -200,9 +200,9 @@ const QString &EffectRow::get_name() {
|
||||
}
|
||||
|
||||
EffectField* EffectRow::field(int i) {
|
||||
return fields.at(i);
|
||||
return fields.at(i);
|
||||
}
|
||||
|
||||
int EffectRow::fieldCount() {
|
||||
return fields.size();
|
||||
return fields.size();
|
||||
}
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
#include "keyframe.h"
|
||||
|
||||
|
||||
EffectKeyframe::EffectKeyframe() {
|
||||
pre_handle_x = -40;
|
||||
pre_handle_y = 0;
|
||||
post_handle_x = 40;
|
||||
post_handle_y = 0;
|
||||
}
|
||||
|
||||
+11
-7
@@ -1,17 +1,21 @@
|
||||
#ifndef KEYFRAME_H
|
||||
#define KEYFRAME_H
|
||||
|
||||
|
||||
|
||||
#include <QVariant>
|
||||
#include <QPoint>
|
||||
|
||||
class KeyframeData
|
||||
{
|
||||
class EffectKeyframe {
|
||||
public:
|
||||
EffectKeyframe();
|
||||
|
||||
long time;
|
||||
int type;
|
||||
QVariant data;
|
||||
QPoint handle_pre;
|
||||
QPoint handle_post;
|
||||
|
||||
// only for bezier type
|
||||
double pre_handle_x;
|
||||
double pre_handle_y;
|
||||
double post_handle_x;
|
||||
double post_handle_y;
|
||||
};
|
||||
|
||||
#endif // KEYFRAME_H
|
||||
|
||||
+20
-20
@@ -738,20 +738,20 @@ void MediaRename::redo() {
|
||||
}
|
||||
|
||||
KeyframeDelete::KeyframeDelete(EffectField *ifield, int iindex) :
|
||||
field(ifield),
|
||||
index(iindex),
|
||||
old_project_changed(mainWindow->isWindowModified())
|
||||
field(ifield),
|
||||
index(iindex),
|
||||
old_project_changed(mainWindow->isWindowModified())
|
||||
{}
|
||||
|
||||
void KeyframeDelete::undo() {
|
||||
field->keyframes.insert(index, deleted_key);
|
||||
field->keyframes.insert(index, deleted_key);
|
||||
mainWindow->setWindowModified(old_project_changed);
|
||||
}
|
||||
|
||||
void KeyframeDelete::redo() {
|
||||
deleted_key = field->keyframes.at(index);
|
||||
field->keyframes.removeAt(index);
|
||||
mainWindow->setWindowModified(true);
|
||||
deleted_key = field->keyframes.at(index);
|
||||
field->keyframes.removeAt(index);
|
||||
mainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
|
||||
@@ -771,7 +771,7 @@ KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
|
||||
if (field->type == EFFECT_FIELD_DOUBLE) {
|
||||
old_values[i] = static_cast<LabelSlider*>(field->ui_element)->getPreviousValue();
|
||||
} else {
|
||||
old_values[i] = field->keyframes.at(index).data;
|
||||
old_values[i] = field->keyframes.at(index).data;
|
||||
}
|
||||
}
|
||||
new_values[i] = field->get_current_data();
|
||||
@@ -781,12 +781,12 @@ KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
|
||||
void KeyframeSet::undo() {
|
||||
if (enable_keyframes) row->setKeyframing(false);
|
||||
|
||||
bool append = (index == -1 || just_made_keyframe);
|
||||
bool append = (index == -1 || just_made_keyframe);
|
||||
for (int i=0;i<row->fieldCount();i++) {
|
||||
if (append) {
|
||||
row->field(i)->keyframes.removeLast();
|
||||
row->field(i)->keyframes.removeLast();
|
||||
} else {
|
||||
row->field(i)->keyframes[index].data = old_values.at(i);
|
||||
row->field(i)->keyframes[index].data = old_values.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,15 +797,15 @@ void KeyframeSet::undo() {
|
||||
void KeyframeSet::redo() {
|
||||
bool append = (index == -1 || (just_made_keyframe && !done));
|
||||
for (int i=0;i<row->fieldCount();i++) {
|
||||
EffectField* f = row->field(i);
|
||||
EffectField* f = row->field(i);
|
||||
if (append) {
|
||||
EffectKeyframe k;
|
||||
k.data = new_values.at(i);
|
||||
k.time = time;
|
||||
k.type = (f->keyframes.size() > 0) ? f->keyframes.last().type : EFFECT_KEYFRAME_LINEAR;
|
||||
f->keyframes.append(k);
|
||||
EffectKeyframe k;
|
||||
k.data = new_values.at(i);
|
||||
k.time = time;
|
||||
k.type = (f->keyframes.size() > 0) ? f->keyframes.last().type : EFFECT_KEYFRAME_LINEAR;
|
||||
f->keyframes.append(k);
|
||||
} else {
|
||||
f->keyframes[index].data = new_values.at(i);
|
||||
f->keyframes[index].data = new_values.at(i);
|
||||
}
|
||||
}
|
||||
row->setKeyframing(true);
|
||||
@@ -1229,9 +1229,9 @@ void RippleAction::redo() {
|
||||
ca->redo();
|
||||
}
|
||||
|
||||
SetDouble::SetDouble(double* pointer, double new_value) :
|
||||
SetDouble::SetDouble(double* pointer, double old_value, double new_value) :
|
||||
p(pointer),
|
||||
oldval(*pointer),
|
||||
oldval(old_value),
|
||||
newval(new_value),
|
||||
old_project_changed(mainWindow->isWindowModified())
|
||||
{}
|
||||
|
||||
+8
-8
@@ -331,21 +331,21 @@ private:
|
||||
|
||||
class KeyframeDelete : public QUndoCommand {
|
||||
public:
|
||||
KeyframeDelete(EffectField* ifield, int iindex);
|
||||
KeyframeDelete(EffectField* ifield, int iindex);
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
EffectField* field;
|
||||
int index;
|
||||
bool done;
|
||||
EffectKeyframe deleted_key;
|
||||
bool old_project_changed;
|
||||
EffectField* field;
|
||||
int index;
|
||||
bool done;
|
||||
EffectKeyframe deleted_key;
|
||||
bool old_project_changed;
|
||||
};
|
||||
|
||||
|
||||
class KeyframeSet : public QUndoCommand {
|
||||
public:
|
||||
KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe);
|
||||
KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe);
|
||||
void undo();
|
||||
void redo();
|
||||
QVector<QVariant> old_values;
|
||||
@@ -523,7 +523,7 @@ private:
|
||||
|
||||
class SetDouble : public QUndoCommand {
|
||||
public:
|
||||
SetDouble(double* pointer, double new_value);
|
||||
SetDouble(double* pointer, double old_value, double new_value);
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user