enforced field semantics and completed shared transitions

This commit is contained in:
itsmattkc
2018-11-24 20:12:51 +11:00
parent c5dca79d1d
commit 00b31d514e
31 changed files with 635 additions and 531 deletions
+2 -2
View File
@@ -68,10 +68,10 @@ void EffectControls::menu_select(QAction* q) {
const EffectMeta* meta = reinterpret_cast<const EffectMeta*>(q->data().value<quintptr>());
if (transition_menu) {
if (c->get_opening_transition() == NULL) {
ca->append(new AddTransitionCommand(c, NULL, meta, TA_OPENING_TRANSITION, 30));
ca->append(new AddTransitionCommand(c, NULL, NULL, meta, TA_OPENING_TRANSITION, 30));
}
if (c->get_closing_transition() == NULL) {
ca->append(new AddTransitionCommand(c, NULL, meta, TA_CLOSING_TRANSITION, 30));
ca->append(new AddTransitionCommand(c, NULL, NULL, meta, TA_CLOSING_TRANSITION, 30));
}
} else {
ca->append(new AddEffectCommand(c, meta));
+175 -97
View File
@@ -808,6 +808,102 @@ QTreeWidgetItem* Project::find_loaded_folder_by_id(int id) {
return NULL;
}
const EffectMeta* get_meta_from_name(const QString& name, int type) {
QVector<EffectMeta>& effect_list = (type == EFFECT_TYPE_VIDEO) ? video_effects : audio_effects;
for (int j=0;j<effect_list.size();j++) {
dout << effect_list.at(j).name << name << (effect_list.at(j).name == name);
if (effect_list.at(j).name == name) {
return &effect_list.at(j);
}
}
return NULL;
}
void load_effect(QXmlStreamReader& stream, Clip* c) {
int effect_id = -1;
QString effect_name;
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") {
effect_id = attr.value().toInt();
} else if (attr.name() == "enabled") {
effect_enabled = (attr.value() == "1");
} else if (attr.name() == "name") {
effect_name = attr.value().toString();
} else if (attr.name() == "length") {
effect_length = attr.value().toLong();
}
}
// backwards compatibility with 180820
if (stream.name() == "effect" && effect_id != -1) {
switch (effect_id) {
case 0: effect_name = (c->track < 0) ? "Transform" : "Volume"; break;
case 1: effect_name = (c->track < 0) ? "Shake" : "Pan"; break;
case 2: effect_name = (c->track < 0) ? "Text" : "Noise"; break;
case 3: effect_name = (c->track < 0) ? "Solid" : "Tone"; break;
case 4: effect_name = "Invert"; break;
case 5: effect_name = "Chroma Key"; break;
case 6: effect_name = "Gaussian Blur"; break;
case 7: effect_name = "Crop"; break;
case 8: effect_name = "Flip"; break;
case 9: effect_name = "Box Blur"; break;
case 10: effect_name = "Wave"; break;
case 11: effect_name = "Temperature"; break;
}
}
// wait for effects to be loaded
effects_loaded.lock();
const EffectMeta* meta = NULL;
// find effect with this name
if (!effect_name.isEmpty()) {
meta = get_meta_from_name(effect_name, (c->track < 0) ? EFFECT_TYPE_VIDEO : EFFECT_TYPE_AUDIO);
}
effects_loaded.unlock();
if (meta == NULL) {
dout << "[WARNING] An effect used by this project is missing. It was not loaded.";
} else {
QString tag = stream.name().toString();
if (tag == "opening" || tag == "closing") {
// TODO replace NULL/s with something else
int transition_index = create_transition(c, NULL, 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 = transition_index;
} else {
c->closing_transition = transition_index;
}
} else {
Effect* e = create_effect(c, meta);
e->set_enabled(effect_enabled);
e->load(stream);
c->effects.append(e);
}
}
}
struct TransitionData {
int id;
QString name;
long length;
Clip* otc;
Clip* ctc;
};
bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
f.seek(0);
stream.setDevice(stream.device());
@@ -968,6 +1064,8 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
}
}
QVector<TransitionData> transition_data;
// load all clips and clip information
while (!(stream.name() == child_search && stream.isEndElement()) && !stream.atEnd()) {
stream.readNextStartElement();
@@ -982,7 +1080,22 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
}
}
s->markers.append(m);
} else if (stream.name() == "clip" && stream.isStartElement()) {
} else if (stream.name() == "transition" && stream.isStartElement()) {
TransitionData td;
td.otc = NULL;
td.ctc = NULL;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "id") {
td.id = attr.value().toInt();
} else if (attr.name() == "name") {
td.name = attr.value().toString();
} else if (attr.name() == "length") {
td.length = attr.value().toLong();
}
}
transition_data.append(td);
} else if (stream.name() == "clip" && stream.isStartElement()) {
int media_id, stream_id;
Clip* c = new Clip(s);
@@ -1027,6 +1140,10 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
c->maintain_audio_pitch = (attr.value() == "1");
} else if (attr.name() == "reverse") {
c->reverse = (attr.value() == "1");
} else if (attr.name() == "opening") {
c->opening_transition = attr.value().toInt();
} else if (attr.name() == "closing") {
c->closing_transition = attr.value().toInt();
} else if (attr.name() == "sequence") {
c->media_type = MEDIA_TYPE_SEQUENCE;
@@ -1072,87 +1189,9 @@ 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;
long effect_length = -1;
for (int j=0;j<stream.attributes().size();j++) {
const QXmlStreamAttribute& attr = stream.attributes().at(j);
if (attr.name() == "id") {
effect_id = attr.value().toInt();
} else if (attr.name() == "enabled") {
effect_enabled = (attr.value() == "1");
} else if (attr.name() == "name") {
effect_name = attr.value().toString();
} else if (attr.name() == "length") {
effect_length = attr.value().toLong();
}
}
// backwards compatibility with 180820
if (stream.name() == "effect" && effect_id != -1) {
switch (effect_id) {
case 0: effect_name = (c->track < 0) ? "Transform" : "Volume"; break;
case 1: effect_name = (c->track < 0) ? "Shake" : "Pan"; break;
case 2: effect_name = (c->track < 0) ? "Text" : "Noise"; break;
case 3: effect_name = (c->track < 0) ? "Solid" : "Tone"; break;
case 4: effect_name = "Invert"; break;
case 5: effect_name = "Chroma Key"; break;
case 6: effect_name = "Gaussian Blur"; break;
case 7: effect_name = "Crop"; break;
case 8: effect_name = "Flip"; break;
case 9: effect_name = "Box Blur"; break;
case 10: effect_name = "Wave"; break;
case 11: effect_name = "Temperature"; break;
}
}
// wait for effects to be loaded
effects_loaded.lock();
const EffectMeta* meta = NULL;
// find effect with this name
if (!effect_name.isEmpty()) {
QVector<EffectMeta>& effect_list = (c->track < 0) ? video_effects : audio_effects;
for (int j=0;j<effect_list.size();j++) {
if (effect_list.at(j).name == effect_name) {
meta = &effect_list.at(j);
break;
}
}
}
effects_loaded.unlock();
if (meta == NULL) {
dout << "[WARNING] An effect used by this project is missing. It was not loaded.";
} else {
QString tag = stream.name().toString();
if (tag == "opening" || tag == "closing") {
// TODO replace NULL/s with somethingn else
int transition_index = create_transition(c, NULL, 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 = transition_index;
} else {
c->closing_transition = transition_index;
}
} else {
Effect* e = create_effect(c, meta);
e->set_enabled(effect_enabled);
e->load(stream);
c->effects.append(e);
}
}
} else if (stream.isStartElement() && (stream.name() == "effect" || stream.name() == "opening" || stream.name() == "closing")) {
// "opening" and "closing" are backwards compatibility code
load_effect(stream, c);
}
}
}
@@ -1161,8 +1200,8 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
}
}
// correct links and clip IDs
for (int i=0;i<s->clips.size();i++) {
// correct links, clip IDs, transitions
for (int i=0;i<s->clips.size();i++) {
// correct links
Clip* correct_clip = s->clips.at(i);
for (int j=0;j<correct_clip->linked.size();j++) {
@@ -1183,6 +1222,44 @@ bool Project::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
}
}
}
// re-link clips to transitions
if (correct_clip->opening_transition > -1) {
for (int j=0;j<transition_data.size();j++) {
if (transition_data.at(j).id == correct_clip->opening_transition) {
transition_data[j].otc = correct_clip;
}
}
}
if (correct_clip->closing_transition > -1) {
for (int j=0;j<transition_data.size();j++) {
if (transition_data.at(j).id == correct_clip->closing_transition) {
transition_data[j].ctc = correct_clip;
}
}
}
}
// create transitions
for (int i=0;i<transition_data.size();i++) {
const TransitionData& td = transition_data.at(i);
Clip* primary = td.otc;
Clip* secondary = td.ctc;
if (primary == NULL) {
primary = secondary;
secondary = NULL;
}
const EffectMeta* meta = get_meta_from_name(td.name, (primary->track < 0) ? EFFECT_TYPE_VIDEO : EFFECT_TYPE_AUDIO);
if (meta == NULL) {
dout << "[WARNING] Failed to link transition with name:" << td.name;
if (td.otc != NULL) td.otc->opening_transition = -1;
if (td.ctc != NULL) td.ctc->closing_transition = -1;
} else {
int transition_index = create_transition(primary, secondary, meta);
primary->sequence->transitions.at(transition_index)->length = td.length;
if (td.otc != NULL) td.otc->opening_transition = transition_index;
if (td.ctc != NULL) td.ctc->closing_transition = transition_index;
}
}
new_sequence(NULL, s, false, parent);
@@ -1414,6 +1491,17 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
stream.writeAttribute("workarea", QString::number(s->using_workarea));
stream.writeAttribute("workareaIn", QString::number(s->workarea_in));
stream.writeAttribute("workareaOut", QString::number(s->workarea_out));
for (int j=0;j<s->transitions.size();j++) {
Transition* t = s->transitions.at(j);
if (t != NULL) {
stream.writeStartElement("transition");
stream.writeAttribute("id", QString::number(j));
t->save(stream);
stream.writeEndElement(); // transition
}
}
for (int j=0;j<s->clips.size();j++) {
Clip* c = s->clips.at(j);
if (c != NULL) {
@@ -1425,6 +1513,8 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
stream.writeAttribute("in", QString::number(c->timeline_in));
stream.writeAttribute("out", QString::number(c->timeline_out));
stream.writeAttribute("track", QString::number(c->track));
stream.writeAttribute("opening", QString::number(c->opening_transition));
stream.writeAttribute("closing", QString::number(c->closing_transition));
stream.writeAttribute("r", QString::number(c->color_r));
stream.writeAttribute("g", QString::number(c->color_g));
@@ -1458,19 +1548,7 @@ void Project::save_folder(QXmlStreamWriter& stream, QTreeWidgetItem* parent, int
stream.writeStartElement("effect"); // effect
c->effects.at(k)->save(stream);
stream.writeEndElement(); // effect
}
if (c->get_opening_transition() != NULL) {
stream.writeStartElement("opening");
c->get_opening_transition()->save(stream);
stream.writeEndElement(); // opening
}
if (c->get_closing_transition() != NULL) {
stream.writeStartElement("closing"); // closing
c->get_closing_transition()->save(stream);
stream.writeEndElement(); // closing
}
}
stream.writeEndElement(); // clip
}
+24 -6
View File
@@ -355,11 +355,11 @@ void Timeline::add_transition() {
Clip* c = sequence->clips.at(i);
if (c != NULL && is_clip_selected(c, true)) {
if (c->get_opening_transition() == NULL) {
ca->append(new AddTransitionCommand(c, NULL, get_internal_meta(TRANSITION_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30));
ca->append(new AddTransitionCommand(c, NULL, NULL, get_internal_meta(TRANSITION_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30));
adding = true;
}
if (c->get_closing_transition() == NULL) {
ca->append(new AddTransitionCommand(c, NULL, get_internal_meta(TRANSITION_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30));
ca->append(new AddTransitionCommand(c, NULL, NULL, get_internal_meta(TRANSITION_INTERNAL_LINEARFADE), TA_OPENING_TRANSITION, 30));
adding = true;
}
}
@@ -634,7 +634,7 @@ Clip* Timeline::split_clip(ComboAction* ca, int p, long frame, long post_in) {
post->timeline_in = post_in;
post->clip_in = pre->clip_in + (post->timeline_in - pre->timeline_in);
ca->append(new MoveClipAction(pre, pre->timeline_in, frame, pre->clip_in, pre->track));
move_clip(ca, pre, pre->timeline_in, frame, pre->clip_in, pre->track);
if (pre->get_opening_transition() != NULL) {
/*if (frame < pre->timeline_in + pre->get_opening_transition()->length && pre->get_opening_transition()->secondary_clip != NULL) {
@@ -792,7 +792,7 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector<Selection>& area
post_clips.append(post);
} else if (c->timeline_in < s.in && c->timeline_out > s.in) {
// only out point is in deletion area
ca->append(new MoveClipAction(c, c->timeline_in, s.in, c->clip_in, c->track));
move_clip(ca, c, c->timeline_in, s.in, c->clip_in, c->track);
if (c->get_closing_transition() != NULL) {
if (s.in < c->timeline_out - c->get_closing_transition()->length) {
@@ -803,7 +803,7 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector<Selection>& area
}
} 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));
move_clip(ca, c, s.out, c->timeline_out, c->clip_in + (s.out - c->timeline_in), c->track);
if (c->get_opening_transition() != NULL) {
if (s.out > c->timeline_in + c->get_opening_transition()->length) {
@@ -1075,7 +1075,7 @@ bool Timeline::split_selection(ComboAction* ca) {
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));
move_clip(ca, clip, clip->timeline_in, s.in, clip->clip_in, clip->track);
split = true;
} else {
Clip* post_a = split_clip(ca, j, s.in);
@@ -1489,3 +1489,21 @@ void Timeline::transition_menu_select(QAction* a) {
tool = TIMELINE_TOOL_TRANSITION;
ui->toolTransitionButton->setChecked(true);
}
void move_clip(ComboAction* ca, Clip *c, long iin, long iout, long iclip_in, int itrack, bool verify_transitions) {
ca->append(new MoveClipAction(c, iin, iout, iclip_in, itrack));
if (verify_transitions) {
if (c->get_opening_transition() != NULL && c->get_opening_transition()->secondary_clip != NULL && c->get_opening_transition()->secondary_clip->timeline_out != iin) {
// separate transition
ca->append(new SetPointer((void**) &c->get_opening_transition()->secondary_clip, NULL));
ca->append(new AddTransitionCommand(c->get_opening_transition()->secondary_clip, NULL, c->get_opening_transition(), NULL, TA_CLOSING_TRANSITION, 0));
}
if (c->get_closing_transition() != NULL && c->get_closing_transition()->secondary_clip != NULL && c->get_closing_transition()->parent_clip->timeline_in != iout) {
// separate transition
ca->append(new SetPointer((void**) &c->get_closing_transition()->secondary_clip, NULL));
ca->append(new AddTransitionCommand(c, NULL, c->get_closing_transition(), NULL, TA_CLOSING_TRANSITION, 0));
}
}
}
+1
View File
@@ -34,6 +34,7 @@ int getScreenPointFromFrame(double zoom, long frame);
long getFrameFromScreenPoint(double zoom, int x);
void draw_selection_rectangle(QPainter& painter, const QRect& rect);
bool selection_contains_transition(const Selection& s, Clip* c, int type);
void move_clip(ComboAction *ca, Clip *c, long iin, long iout, long iclip_in, int itrack, bool verify_transitions = true);
struct Ghost {
int clip;