enforced field semantics and completed shared transitions
This commit is contained in:
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user