Merge branch 'master' into new_timecode
This commit is contained in:
@@ -314,7 +314,7 @@ void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, lo
|
||||
}
|
||||
ep = qMin(ep, c->timeline_out);
|
||||
lr = qMax(lr, proposed_out - c->timeline_out);
|
||||
ca->append(new MoveClipAction(c, c->timeline_in, proposed_out, c->clip_in * multiplier, c->track));
|
||||
move_clip(ca, c, c->timeline_in, proposed_out, c->clip_in * multiplier, c->track);
|
||||
|
||||
c->refactor_frame_rate(ca, multiplier, false);
|
||||
|
||||
@@ -346,7 +346,7 @@ void SpeedDialog::accept() {
|
||||
|
||||
if (reverse->checkState() != Qt::PartiallyChecked && c->reverse != reverse->isChecked()) {
|
||||
long new_clip_in = (c->getMaximumLength() - (c->getLength() + c->clip_in));
|
||||
ca->append(new MoveClipAction(c, c->timeline_in, c->timeline_out, new_clip_in, c->track));
|
||||
move_clip(ca, c, c->timeline_in, c->timeline_out, new_clip_in, c->track);
|
||||
c->clip_in = new_clip_in;
|
||||
ca->append(new SetBool(&c->reverse, reverse->isChecked()));
|
||||
}
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
#include <QtMath>
|
||||
|
||||
AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE);
|
||||
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE, "amount");
|
||||
amount_val->set_double_minimum_value(0);
|
||||
amount_val->set_double_maximum_value(100);
|
||||
amount_val->set_double_default_value(20);
|
||||
amount_val->id = "amount";
|
||||
amount_val->set_double_default_value(20);
|
||||
|
||||
mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL);
|
||||
mix_val->id = "mix";
|
||||
mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL, "mix");
|
||||
mix_val->set_bool_value(true);
|
||||
|
||||
srand(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(mix_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
srand(QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
|
||||
void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
|
||||
|
||||
@@ -9,41 +9,28 @@ CornerPinEffect::CornerPinEffect(Clip *c, const EffectMeta *em) : Effect(c, em)
|
||||
enable_shader = true;
|
||||
|
||||
EffectRow* top_left = add_row("Top Left:");
|
||||
top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE);
|
||||
top_left_x->id = "topleftx";
|
||||
top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE);
|
||||
top_left_y->id = "toplefty";
|
||||
top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx");
|
||||
top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty");
|
||||
|
||||
EffectRow* top_right = add_row("Top Right:");
|
||||
top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE);
|
||||
top_right_x->id = "toprightx";
|
||||
top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE);
|
||||
top_right_y->id = "toprighty";
|
||||
top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx");
|
||||
top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty");
|
||||
|
||||
EffectRow* bottom_left = add_row("Bottom Left:");
|
||||
bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE);
|
||||
bottom_left_x->id = "bottomleftx";
|
||||
bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE);
|
||||
bottom_left_y->id = "bottomlefty";
|
||||
bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx");
|
||||
bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty");
|
||||
|
||||
EffectRow* bottom_right = add_row("Bottom Right:");
|
||||
bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE);
|
||||
bottom_right_x->id = "bottomrightx";
|
||||
bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE);
|
||||
bottom_right_y->id = "bottomrighty";
|
||||
bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx");
|
||||
bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty");
|
||||
|
||||
perspective = add_row("Perspective:")->add_field(EFFECT_FIELD_BOOL);
|
||||
perspective->set_bool_value(true);
|
||||
perspective = add_row("Perspective:")->add_field(EFFECT_FIELD_BOOL, "perspective");
|
||||
perspective->set_bool_value(true);
|
||||
|
||||
connect(top_left_x, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(top_left_y, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(top_right_x, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(top_right_y, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(bottom_left_x, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(bottom_left_y, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(bottom_right_x, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(bottom_right_y, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(perspective, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
|
||||
vertPath = "cornerpin.vert";
|
||||
fragPath = "cornerpin.frag";
|
||||
@@ -68,5 +55,28 @@ void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords) {
|
||||
glslProgram->setUniformValue("p1", (GLfloat) coords.vertexBottomRightX, (GLfloat) coords.vertexBottomRightY);
|
||||
glslProgram->setUniformValue("p2", (GLfloat) coords.vertexTopLeftX, (GLfloat) coords.vertexTopLeftY);
|
||||
glslProgram->setUniformValue("p3", (GLfloat) coords.vertexTopRightX, (GLfloat) coords.vertexTopRightY);
|
||||
glslProgram->setUniformValue("perspective", perspective->get_bool_value(timecode));
|
||||
glslProgram->setUniformValue("perspective", perspective->get_bool_value(timecode));
|
||||
}
|
||||
|
||||
void CornerPinEffect::gizmo_draw(double timecode, GLTextureCoords &coords) {
|
||||
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
||||
top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
||||
bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
||||
bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
||||
}
|
||||
|
||||
void CornerPinEffect::gizmo_move(EffectGizmo *sender, int x_movement, int y_movement, double timecode) {
|
||||
if (sender == bottom_right_gizmo) {
|
||||
bottom_right_x->set_double_value(bottom_right_x->get_double_value(timecode) + x_movement);
|
||||
bottom_right_y->set_double_value(bottom_right_y->get_double_value(timecode) + y_movement);
|
||||
} else if (sender == top_left_gizmo) {
|
||||
top_left_x->set_double_value(top_left_x->get_double_value(timecode) + x_movement);
|
||||
top_left_y->set_double_value(top_left_y->get_double_value(timecode) + y_movement);
|
||||
} else if (sender == bottom_left_gizmo) {
|
||||
bottom_left_x->set_double_value(bottom_left_x->get_double_value(timecode) + x_movement);
|
||||
bottom_left_y->set_double_value(bottom_left_y->get_double_value(timecode) + y_movement);
|
||||
} else if (sender == top_right_gizmo) {
|
||||
top_right_x->set_double_value(top_right_x->get_double_value(timecode) + x_movement);
|
||||
top_right_y->set_double_value(top_right_y->get_double_value(timecode) + y_movement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ public:
|
||||
CornerPinEffect(Clip* c, const EffectMeta* em);
|
||||
void process_coords(double timecode, GLTextureCoords& coords, int data);
|
||||
void process_shader(double timecode, GLTextureCoords& coords);
|
||||
void gizmo_draw(double timecode, GLTextureCoords& coords);
|
||||
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode);
|
||||
private:
|
||||
EffectField* top_left_x;
|
||||
EffectField* top_left_y;
|
||||
@@ -19,6 +21,11 @@ private:
|
||||
EffectField* bottom_right_x;
|
||||
EffectField* bottom_right_y;
|
||||
EffectField* perspective;
|
||||
|
||||
EffectGizmo* top_left_gizmo;
|
||||
EffectGizmo* top_right_gizmo;
|
||||
EffectGizmo* bottom_left_gizmo;
|
||||
EffectGizmo* bottom_right_gizmo;
|
||||
};
|
||||
|
||||
#endif // CORNERPINEFFECT_H
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
CrossDissolveTransition::CrossDissolveTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) {
|
||||
enable_coords = true;
|
||||
|
||||
// add_row("Smooth")->add_field(EFFECT_FIELD_BOOL, "smooth");
|
||||
}
|
||||
|
||||
void CrossDissolveTransition::process_coords(double progress, GLTextureCoords&, int data) {
|
||||
|
||||
@@ -6,6 +6,8 @@ CubeTransition::CubeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transit
|
||||
enable_coords = true;
|
||||
}
|
||||
|
||||
void CubeTransition::process_coords(double progress, GLTextureCoords&, int data) {
|
||||
glTranslatef(-progress, 0, -progress);
|
||||
void CubeTransition::process_coords(double progress, GLTextureCoords& coords, int data) {
|
||||
|
||||
coords.vertexTopLeftZ = 1;
|
||||
coords.vertexBottomLeftZ = 1;
|
||||
}
|
||||
|
||||
@@ -9,16 +9,13 @@
|
||||
#include "ui/collapsiblewidget.h"
|
||||
|
||||
PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||
EffectRow* pan_row = add_row("Pan:");
|
||||
pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE);
|
||||
EffectRow* pan_row = add_row("Pan:");
|
||||
pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE, "pan");
|
||||
pan_val->set_double_minimum_value(-100);
|
||||
pan_val->set_double_maximum_value(100);
|
||||
pan_val->id = "pan";
|
||||
pan_val->set_double_maximum_value(100);
|
||||
|
||||
// set defaults
|
||||
pan_val->set_double_default_value(0);
|
||||
|
||||
connect(pan_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
pan_val->set_double_default_value(0);
|
||||
}
|
||||
|
||||
void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
||||
|
||||
@@ -17,18 +17,15 @@ ShakeEffect::ShakeEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
|
||||
enable_coords = true;
|
||||
|
||||
EffectRow* intensity_row = add_row("Intensity:");
|
||||
intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE);
|
||||
intensity_val->id = "intensity";
|
||||
intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE, "intensity");
|
||||
intensity_val->set_double_minimum_value(0);
|
||||
|
||||
EffectRow* rotation_row = add_row("Rotation:");
|
||||
rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE);
|
||||
rotation_val->id = "rotation";
|
||||
rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
|
||||
rotation_val->set_double_minimum_value(0);
|
||||
|
||||
EffectRow* frequency_row = add_row("Frequency:");
|
||||
frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE);
|
||||
frequency_val->id = "frequency";
|
||||
frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE, "frequency");
|
||||
frequency_val->set_double_minimum_value(0);
|
||||
|
||||
// set defaults
|
||||
@@ -41,10 +38,6 @@ ShakeEffect::ShakeEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
|
||||
for (int i=0;i<RANDOM_VAL_SIZE;i++) {
|
||||
random_vals[i] = (double)rand()/RAND_MAX;
|
||||
}
|
||||
|
||||
connect(intensity_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(rotation_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(frequency_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
}
|
||||
|
||||
void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int data) {
|
||||
|
||||
@@ -21,31 +21,22 @@
|
||||
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
||||
enable_superimpose = true;
|
||||
|
||||
solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO);
|
||||
solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO, "type");
|
||||
solid_type->add_combo_item("Solid Color", SOLID_TYPE_COLOR);
|
||||
solid_type->add_combo_item("SMPTE Bars", SOLID_TYPE_BARS);
|
||||
solid_type->add_combo_item("Checkerboard", SOLID_TYPE_CHECKERBOARD);
|
||||
solid_type->id = "type";
|
||||
|
||||
opacity_field = add_row("Opacity:")->add_field(EFFECT_FIELD_DOUBLE);
|
||||
opacity_field = add_row("Opacity:")->add_field(EFFECT_FIELD_DOUBLE, "opacity");
|
||||
opacity_field->set_double_minimum_value(0);
|
||||
opacity_field->set_double_maximum_value(100);
|
||||
opacity_field->set_double_default_value(100);
|
||||
opacity_field->id = "opacity";
|
||||
|
||||
solid_color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR);
|
||||
solid_color_field->set_color_value(Qt::red);
|
||||
solid_color_field->id = "color";
|
||||
solid_color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, "color");
|
||||
solid_color_field->set_color_value(Qt::red);
|
||||
|
||||
checkerboard_size_field = add_row("Checkerboard Size:")->add_field(EFFECT_FIELD_DOUBLE);
|
||||
checkerboard_size_field = add_row("Checkerboard Size:")->add_field(EFFECT_FIELD_DOUBLE, "checker_size");
|
||||
checkerboard_size_field->set_double_minimum_value(1);
|
||||
checkerboard_size_field->set_double_default_value(10);
|
||||
checkerboard_size_field->id = "checker_size";
|
||||
|
||||
connect(solid_type, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(solid_color_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(opacity_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(checkerboard_size_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
|
||||
// hacky but eh
|
||||
QComboBox* solid_type_combo = static_cast<QComboBox*>(solid_type->get_ui_element());
|
||||
@@ -59,7 +50,7 @@ SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
||||
void SolidEffect::redraw(double timecode) {
|
||||
int w = img.width();
|
||||
int h = img.height();
|
||||
int alpha = (opacity_field->get_double_value(timecode)*2.55);
|
||||
int alpha = qRound(opacity_field->get_double_value(timecode)*2.55);
|
||||
switch (solid_type->get_combo_data(timecode).toInt()) {
|
||||
case SOLID_TYPE_COLOR:
|
||||
{
|
||||
|
||||
@@ -24,56 +24,41 @@ TextEffect::TextEffect(Clip *c, const EffectMeta* em) :
|
||||
{
|
||||
enable_superimpose = true;
|
||||
|
||||
text_val = add_row("Text:")->add_field(EFFECT_FIELD_STRING, 2);
|
||||
text_val->id = "text";
|
||||
text_val = add_row("Text:")->add_field(EFFECT_FIELD_STRING, "text", 2);
|
||||
|
||||
set_font_combobox = add_row("Font:")->add_field(EFFECT_FIELD_FONT, 2);
|
||||
set_font_combobox->id = "font";
|
||||
set_font_combobox = add_row("Font:")->add_field(EFFECT_FIELD_FONT, "font", 2);
|
||||
|
||||
size_val = add_row("Size:")->add_field(EFFECT_FIELD_DOUBLE, 2);
|
||||
size_val->set_double_minimum_value(0);
|
||||
size_val->id = "size";
|
||||
size_val = add_row("Size:")->add_field(EFFECT_FIELD_DOUBLE, "size", 2);
|
||||
size_val->set_double_minimum_value(0);
|
||||
|
||||
set_color_button = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, 2);
|
||||
set_color_button->id = "color";
|
||||
set_color_button = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
||||
|
||||
EffectRow* alignment_row = add_row("Alignment:");
|
||||
halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO);
|
||||
halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "halign");
|
||||
halign_field->add_combo_item("Left", Qt::AlignLeft);
|
||||
halign_field->add_combo_item("Center", Qt::AlignHCenter);
|
||||
halign_field->add_combo_item("Right", Qt::AlignRight);
|
||||
halign_field->add_combo_item("Justify", Qt::AlignJustify);
|
||||
halign_field->id = "halign";
|
||||
halign_field->add_combo_item("Justify", Qt::AlignJustify);
|
||||
|
||||
valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO);
|
||||
valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "valign");
|
||||
valign_field->add_combo_item("Top", Qt::AlignTop);
|
||||
valign_field->add_combo_item("Center", Qt::AlignVCenter);
|
||||
valign_field->add_combo_item("Bottom", Qt::AlignBottom);
|
||||
valign_field->id = "valign";
|
||||
valign_field->add_combo_item("Bottom", Qt::AlignBottom);
|
||||
|
||||
word_wrap_field = add_row("Word Wrap:")->add_field(EFFECT_FIELD_BOOL, 2);
|
||||
word_wrap_field->id = "wordwrap";
|
||||
word_wrap_field = add_row("Word Wrap:")->add_field(EFFECT_FIELD_BOOL, "wordwrap", 2);
|
||||
|
||||
outline_bool = add_row("Outline:")->add_field(EFFECT_FIELD_BOOL, 2);
|
||||
outline_bool->id = "outline";
|
||||
outline_color = add_row("Outline Color:")->add_field(EFFECT_FIELD_COLOR, 2);
|
||||
outline_color->id = "outlinecolor";
|
||||
outline_width = add_row("Outline Width:")->add_field(EFFECT_FIELD_DOUBLE, 2);
|
||||
outline_width->id = "outlinewidth";
|
||||
outline_bool = add_row("Outline:")->add_field(EFFECT_FIELD_BOOL, "outline", 2);
|
||||
outline_color = add_row("Outline Color:")->add_field(EFFECT_FIELD_COLOR, "outlinecolor", 2);
|
||||
outline_width = add_row("Outline Width:")->add_field(EFFECT_FIELD_DOUBLE, "outlinewidth", 2);
|
||||
outline_width->set_double_minimum_value(0);
|
||||
|
||||
shadow_bool = add_row("Shadow:")->add_field(EFFECT_FIELD_BOOL, 2);
|
||||
shadow_bool->id = "shadow";
|
||||
shadow_color = add_row("Shadow Color:")->add_field(EFFECT_FIELD_COLOR, 2);
|
||||
shadow_color->id = "shadowcolor";
|
||||
shadow_distance = add_row("Shadow Distance:")->add_field(EFFECT_FIELD_DOUBLE, 2);
|
||||
shadow_distance->id = "shadowdistance";
|
||||
shadow_bool = add_row("Shadow:")->add_field(EFFECT_FIELD_BOOL, "shadow", 2);
|
||||
shadow_color = add_row("Shadow Color:")->add_field(EFFECT_FIELD_COLOR, "shadowcolor", 2);
|
||||
shadow_distance = add_row("Shadow Distance:")->add_field(EFFECT_FIELD_DOUBLE, "shadowdistance", 2);
|
||||
shadow_distance->set_double_minimum_value(0);
|
||||
shadow_softness = add_row("Shadow Softness:")->add_field(EFFECT_FIELD_DOUBLE, 2);
|
||||
shadow_softness->id = "shadowsoftness";
|
||||
shadow_softness = add_row("Shadow Softness:")->add_field(EFFECT_FIELD_DOUBLE, "shadowsoftness", 2);
|
||||
shadow_softness->set_double_minimum_value(0);
|
||||
shadow_opacity = add_row("Shadow Opacity:")->add_field(EFFECT_FIELD_DOUBLE, 2);
|
||||
shadow_opacity->id = "shadowopacity";
|
||||
shadow_opacity = add_row("Shadow Opacity:")->add_field(EFFECT_FIELD_DOUBLE, "shadowopacity", 2);
|
||||
shadow_opacity->set_double_minimum_value(0);
|
||||
shadow_opacity->set_double_maximum_value(100);
|
||||
|
||||
@@ -91,23 +76,7 @@ TextEffect::TextEffect(Clip *c, const EffectMeta* em) :
|
||||
outline_width->set_double_default_value(20);
|
||||
|
||||
outline_enable(false);
|
||||
shadow_enable(false);
|
||||
|
||||
connect(text_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(size_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(set_color_button, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(set_font_combobox, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(halign_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(valign_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(word_wrap_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(outline_bool, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(outline_color, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(outline_width, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(shadow_bool, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(shadow_color, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(shadow_distance, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(shadow_softness, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(shadow_opacity, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
shadow_enable(false);
|
||||
|
||||
connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool)));
|
||||
connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool)));
|
||||
|
||||
@@ -9,29 +9,21 @@
|
||||
#include "debug.h"
|
||||
|
||||
ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) {
|
||||
type_val = add_row("Type:")->add_field(EFFECT_FIELD_COMBO);
|
||||
type_val->id = "type";
|
||||
type_val = add_row("Type:")->add_field(EFFECT_FIELD_COMBO, "type");
|
||||
type_val->add_combo_item("Sine", TONE_TYPE_SINE);
|
||||
|
||||
freq_val = add_row("Frequency:")->add_field(EFFECT_FIELD_DOUBLE);
|
||||
freq_val->id = "frequency";
|
||||
freq_val = add_row("Frequency:")->add_field(EFFECT_FIELD_DOUBLE, "frequency");
|
||||
freq_val->set_double_minimum_value(20);
|
||||
freq_val->set_double_maximum_value(20000);
|
||||
freq_val->set_double_default_value(1000);
|
||||
|
||||
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE);
|
||||
amount_val->id = "amount";
|
||||
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE, "amount");
|
||||
amount_val->set_double_minimum_value(0);
|
||||
amount_val->set_double_maximum_value(100);
|
||||
amount_val->set_double_default_value(25);
|
||||
|
||||
mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL);
|
||||
mix_val->id = "mix";
|
||||
mix_val->set_bool_value(true);
|
||||
|
||||
connect(freq_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(mix_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL, "mix");
|
||||
mix_val->set_bool_value(true);
|
||||
}
|
||||
|
||||
void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "transformeffect.h"
|
||||
#include "transformeffect.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
@@ -7,89 +7,97 @@
|
||||
#include <QCheckBox>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QComboBox>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "project/clip.h"
|
||||
#include "project/sequence.h"
|
||||
#include "io/media.h"
|
||||
#include "io/math.h"
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/comboboxex.h"
|
||||
#include "panels/project.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "panels/panels.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "ui/viewerwidget.h"
|
||||
|
||||
#define BLEND_MODE_NORMAL 0
|
||||
#define BLEND_MODE_SCREEN 1
|
||||
#define BLEND_MODE_MULTIPLY 2
|
||||
#define BLEND_MODE_OVERLAY 3
|
||||
|
||||
TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
||||
enable_coords = true;
|
||||
TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
||||
enable_coords = true;
|
||||
|
||||
EffectRow* position_row = add_row("Position:");
|
||||
position_x = position_row->add_field(EFFECT_FIELD_DOUBLE); // position X
|
||||
position_x->id = "posx";
|
||||
position_y = position_row->add_field(EFFECT_FIELD_DOUBLE); // position Y
|
||||
position_y->id = "posy";
|
||||
position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X
|
||||
position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y
|
||||
|
||||
EffectRow* scale_row = add_row("Scale:");
|
||||
scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE); // scale X (and Y is uniform scale is selected)
|
||||
scale_x->id = "scalex";
|
||||
scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected)
|
||||
scale_x->set_double_minimum_value(0);
|
||||
scale_x->set_double_maximum_value(3000);
|
||||
scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE); // scale Y (disabled if uniform scale is selected)
|
||||
scale_y->id = "scaley";
|
||||
scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected)
|
||||
scale_y->set_double_minimum_value(0);
|
||||
scale_y->set_double_maximum_value(3000);
|
||||
|
||||
EffectRow* uniform_scale_row = add_row("Uniform Scale:");
|
||||
uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL); // uniform scale option
|
||||
uniform_scale_field->id = "uniformscale";
|
||||
uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option
|
||||
|
||||
EffectRow* rotation_row = add_row("Rotation:");
|
||||
rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE);
|
||||
rotation->id = "rotation";
|
||||
rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
|
||||
|
||||
EffectRow* anchor_point_row = add_row("Anchor Point:");
|
||||
anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE); // anchor point X
|
||||
anchor_x_box->id = "anchorx";
|
||||
anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE); // anchor point Y
|
||||
anchor_y_box->id = "anchory";
|
||||
anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchorx"); // anchor point X
|
||||
anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchory"); // anchor point Y
|
||||
|
||||
EffectRow* opacity_row = add_row("Opacity:");
|
||||
opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE); // opacity
|
||||
opacity->id = "opacity";
|
||||
opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity
|
||||
opacity->set_double_minimum_value(0);
|
||||
opacity->set_double_maximum_value(100);
|
||||
|
||||
EffectRow* blend_mode_row = add_row("Blend Mode:");
|
||||
blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO); // blend mode
|
||||
blend_mode_box->id = "blendmode";
|
||||
blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode"); // blend mode
|
||||
blend_mode_box->add_combo_item("Normal", BLEND_MODE_NORMAL);
|
||||
blend_mode_box->add_combo_item("Overlay", BLEND_MODE_OVERLAY);
|
||||
blend_mode_box->add_combo_item("Screen", BLEND_MODE_SCREEN);
|
||||
blend_mode_box->add_combo_item("Multiply", BLEND_MODE_MULTIPLY);
|
||||
|
||||
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||
rect_gizmo = add_gizmo(GIZMO_TYPE_POLY);
|
||||
|
||||
top_left_gizmo->set_cursor(Qt::SizeFDiagCursor);
|
||||
top_center_gizmo->set_cursor(Qt::SizeVerCursor);
|
||||
top_right_gizmo->set_cursor(Qt::SizeBDiagCursor);
|
||||
bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor);
|
||||
bottom_center_gizmo->set_cursor(Qt::SizeVerCursor);
|
||||
bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor);
|
||||
left_center_gizmo->set_cursor(Qt::SizeHorCursor);
|
||||
right_center_gizmo->set_cursor(Qt::SizeHorCursor);
|
||||
rotate_gizmo->color = Qt::green;
|
||||
rotate_gizmo->set_cursor(Qt::SizeAllCursor);
|
||||
|
||||
// set defaults
|
||||
scale_y->set_enabled(false);
|
||||
uniform_scale_field->set_bool_value(true);
|
||||
blend_mode_box->set_combo_index(0);
|
||||
refresh();
|
||||
|
||||
connect(position_x, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(position_y, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(scale_x, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(scale_y, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(uniform_scale_field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(rotation, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(anchor_x_box, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(anchor_y_box, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(opacity, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(blend_mode_box, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
|
||||
}
|
||||
|
||||
void TransformEffect::refresh() {
|
||||
if (parent_clip->sequence != NULL) {
|
||||
if (parent_clip != NULL && parent_clip->sequence != NULL) {
|
||||
double default_pos_x = parent_clip->sequence->width/2;
|
||||
double default_pos_y = parent_clip->sequence->height/2;
|
||||
|
||||
@@ -131,7 +139,7 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i
|
||||
coords.vertexBottomRightY -= anchor_y_offset;
|
||||
|
||||
// rotation
|
||||
glRotatef(rotation->get_double_value(timecode), 0, 0, 1);
|
||||
glRotatef(rotation->get_double_value(timecode), 0, 0, 1);
|
||||
|
||||
// scale
|
||||
float sx = scale_x->get_double_value(timecode)*0.01;
|
||||
@@ -159,5 +167,64 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i
|
||||
// opacity
|
||||
float color[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, color);
|
||||
glColor4f(1.0, 1.0, 1.0, color[3]*(opacity->get_double_value(timecode)*0.01));
|
||||
glColor4f(1.0, 1.0, 1.0, color[3]*(opacity->get_double_value(timecode)*0.01));
|
||||
}
|
||||
|
||||
void TransformEffect::gizmo_draw(double timecode, GLTextureCoords& coords) {
|
||||
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
||||
top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5));
|
||||
top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
||||
right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5));
|
||||
bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
||||
bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5));
|
||||
bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
||||
left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5));
|
||||
|
||||
rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1));
|
||||
|
||||
rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
||||
rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
||||
rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
||||
rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
||||
}
|
||||
|
||||
void TransformEffect::gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode) {
|
||||
double x_percent = ((double) x_movement / parent_clip->sequence->width)*200;
|
||||
double y_percent = ((double) y_movement / parent_clip->sequence->height)*200;
|
||||
|
||||
if (sender == bottom_right_gizmo) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) + x_percent);
|
||||
if (!uniform_scale_field->get_bool_value(timecode)) scale_y->set_double_value(scale_y->get_double_value(timecode) + y_percent);
|
||||
} else if (sender == top_left_gizmo) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) - x_percent);
|
||||
if (!uniform_scale_field->get_bool_value(timecode)) scale_y->set_double_value(scale_y->get_double_value(timecode) - y_percent);
|
||||
} else if (sender == bottom_left_gizmo) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) - x_percent);
|
||||
if (!uniform_scale_field->get_bool_value(timecode)) scale_y->set_double_value(scale_y->get_double_value(timecode) + y_percent);
|
||||
} else if (sender == top_right_gizmo) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) + x_percent);
|
||||
if (!uniform_scale_field->get_bool_value(timecode)) scale_y->set_double_value(scale_y->get_double_value(timecode) - y_percent);
|
||||
} else if (sender == left_center_gizmo) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) - x_percent);
|
||||
} else if (sender == right_center_gizmo) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) + x_percent);
|
||||
} else if (sender == top_center_gizmo) {
|
||||
if (uniform_scale_field->get_bool_value(timecode)) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) - y_percent);
|
||||
} else {
|
||||
scale_y->set_double_value(scale_y->get_double_value(timecode) - y_percent);
|
||||
}
|
||||
} else if (sender == bottom_center_gizmo) {
|
||||
if (uniform_scale_field->get_bool_value(timecode)) {
|
||||
scale_x->set_double_value(scale_x->get_double_value(timecode) + y_percent);
|
||||
} else {
|
||||
scale_y->set_double_value(scale_y->get_double_value(timecode) + y_percent);
|
||||
}
|
||||
} else if (sender == rotate_gizmo) {
|
||||
// TODO make this perfectly circular
|
||||
rotation->set_double_value(rotation->get_double_value(timecode) + x_percent);
|
||||
} else {
|
||||
position_x->set_double_value(position_x->get_double_value(timecode) + x_movement);
|
||||
position_y->set_double_value(position_y->get_double_value(timecode) + y_movement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,21 +10,35 @@ public:
|
||||
void refresh();
|
||||
void process_coords(double timecode, GLTextureCoords& coords, int data);
|
||||
|
||||
EffectField* position_x;
|
||||
EffectField* position_y;
|
||||
EffectField* scale_x;
|
||||
EffectField* scale_y;
|
||||
EffectField* uniform_scale_field;
|
||||
EffectField* rotation;
|
||||
EffectField* anchor_x_box;
|
||||
EffectField* anchor_y_box;
|
||||
EffectField* opacity;
|
||||
EffectField* blend_mode_box;
|
||||
void gizmo_draw(double timecode, GLTextureCoords& coords);
|
||||
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode);
|
||||
public slots:
|
||||
void toggle_uniform_scale(bool enabled);
|
||||
private:
|
||||
EffectField* position_x;
|
||||
EffectField* position_y;
|
||||
EffectField* scale_x;
|
||||
EffectField* scale_y;
|
||||
EffectField* uniform_scale_field;
|
||||
EffectField* rotation;
|
||||
EffectField* anchor_x_box;
|
||||
EffectField* anchor_y_box;
|
||||
EffectField* opacity;
|
||||
EffectField* blend_mode_box;
|
||||
|
||||
EffectGizmo* top_left_gizmo;
|
||||
EffectGizmo* top_center_gizmo;
|
||||
EffectGizmo* top_right_gizmo;
|
||||
EffectGizmo* bottom_left_gizmo;
|
||||
EffectGizmo* bottom_center_gizmo;
|
||||
EffectGizmo* bottom_right_gizmo;
|
||||
EffectGizmo* left_center_gizmo;
|
||||
EffectGizmo* right_center_gizmo;
|
||||
EffectGizmo* rotate_gizmo;
|
||||
EffectGizmo* rect_gizmo;
|
||||
|
||||
int default_anchor_x;
|
||||
int default_anchor_y;
|
||||
int default_anchor_y;
|
||||
};
|
||||
|
||||
#endif // TRANSFORMEFFECT_H
|
||||
|
||||
@@ -9,15 +9,12 @@
|
||||
#include "ui/collapsiblewidget.h"
|
||||
|
||||
VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||
EffectRow* volume_row = add_row("Volume:");
|
||||
volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE);
|
||||
volume_val->id = "volume";
|
||||
EffectRow* volume_row = add_row("Volume:");
|
||||
volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume");
|
||||
volume_val->set_double_minimum_value(0);
|
||||
|
||||
// set defaults
|
||||
volume_val->set_double_default_value(100);
|
||||
|
||||
connect(volume_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
volume_val->set_double_default_value(100);
|
||||
}
|
||||
|
||||
void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "clipboard.h"
|
||||
|
||||
#include "project/clip.h"
|
||||
|
||||
int clipboard_type = CLIPBOARD_TYPE_CLIP;
|
||||
QVector<void*> clipboard;
|
||||
|
||||
void clear_clipboard() {
|
||||
for (int i=0;i<clipboard.size();i++) {
|
||||
if (clipboard_type == CLIPBOARD_TYPE_CLIP) {
|
||||
delete static_cast<Clip*>(clipboard.at(i));
|
||||
} else if (clipboard_type == CLIPBOARD_TYPE_EFFECT) {
|
||||
delete static_cast<Effect*>(clipboard.at(i));
|
||||
}
|
||||
}
|
||||
clipboard.clear();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef CLIPBOARD_H
|
||||
#define CLIPBOARD_H
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#define CLIPBOARD_TYPE_CLIP 0
|
||||
#define CLIPBOARD_TYPE_EFFECT 1
|
||||
|
||||
extern int clipboard_type;
|
||||
extern QVector<void*> clipboard;
|
||||
void clear_clipboard();
|
||||
|
||||
#endif // CLIPBOARD_H
|
||||
+3
-2
@@ -3,12 +3,13 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#define SAVE_VERSION 181114 // YYMMDD
|
||||
#define MIN_SAVE_VERSION 180820 // lowest compatible project version
|
||||
#define SAVE_VERSION 181124 // YYMMDD
|
||||
#define MIN_SAVE_VERSION 181114 // lowest compatible project version
|
||||
|
||||
#define TIMECODE_DROP 0
|
||||
#define TIMECODE_NONDROP 1
|
||||
#define TIMECODE_FRAMES 2
|
||||
#define TIMECODE_MILLISECONDS 3
|
||||
|
||||
#define RECORD_MODE_MONO 1
|
||||
#define RECORD_MODE_STEREO 2
|
||||
|
||||
@@ -6,6 +6,10 @@ int lerp(int a, int b, double t) {
|
||||
return qRound(((1.0 - t) * a) + (t * b));
|
||||
}
|
||||
|
||||
float float_lerp(float a, float b, float t) {
|
||||
return ((1.0F - t) * a) + (t * b);
|
||||
}
|
||||
|
||||
double double_lerp(double a, double b, double t) {
|
||||
return ((1.0 - t) * a) + (t * b);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MATH_H
|
||||
|
||||
int lerp(int a, int b, double t);
|
||||
float float_lerp(float a, float b, float t);
|
||||
double double_lerp(double a, double b, double t);
|
||||
|
||||
#endif // MATH_H
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ struct MediaStream {
|
||||
|
||||
// preview thumbnail/waveform
|
||||
bool preview_done;
|
||||
QPixmap video_preview;
|
||||
QImage video_preview;
|
||||
QVector<char> audio_preview;
|
||||
};
|
||||
|
||||
|
||||
@@ -124,10 +124,9 @@ bool PreviewGenerator::retrieve_preview(const QString& hash) {
|
||||
MediaStream* ms = media->video_tracks.at(i);
|
||||
QString thumb_path = get_thumbnail_path(hash, ms);
|
||||
QFile f(thumb_path);
|
||||
if (f.exists()) {
|
||||
if (f.exists() && ms->video_preview.load(thumb_path)) {
|
||||
//dout << "loaded thumb" << ms->file_index << "from" << thumb_path;
|
||||
ms->video_preview.load(thumb_path);
|
||||
ms->preview_done = true;
|
||||
ms->preview_done = true;
|
||||
} else {
|
||||
found = false;
|
||||
break;
|
||||
@@ -270,7 +269,7 @@ void PreviewGenerator::generate_waveform() {
|
||||
linesize[0] = dstW*3;
|
||||
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize);
|
||||
|
||||
s->video_preview.convertFromImage(QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888));
|
||||
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
|
||||
|
||||
// is video interlaced?
|
||||
s->video_auto_interlacing = (temp_frame->interlaced_frame) ? ((temp_frame->top_field_first) ? VIDEO_TOP_FIELD_FIRST : VIDEO_BOTTOM_FIELD_FIRST) : VIDEO_PROGRESSIVE;
|
||||
|
||||
+21
-7
@@ -385,19 +385,27 @@ void MainWindow::openSpeedDialog() {
|
||||
}
|
||||
|
||||
void MainWindow::cut() {
|
||||
if (panel_timeline->focused() && sequence != NULL) {
|
||||
panel_timeline->copy(true);
|
||||
}
|
||||
if (sequence != NULL) {
|
||||
if (panel_timeline->focused()) {
|
||||
panel_timeline->copy(true);
|
||||
} else if (panel_effect_controls->is_focused()) {
|
||||
panel_effect_controls->copy(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::copy() {
|
||||
if (panel_timeline->focused() && sequence != NULL) {
|
||||
panel_timeline->copy(false);
|
||||
}
|
||||
if (sequence != NULL) {
|
||||
if (panel_timeline->focused()) {
|
||||
panel_timeline->copy(false);
|
||||
} else if (panel_effect_controls->is_focused()) {
|
||||
panel_effect_controls->copy(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::paste() {
|
||||
if (panel_timeline->focused() && sequence != NULL) {
|
||||
if ((panel_timeline->focused() || panel_effect_controls->is_focused()) && sequence != NULL) {
|
||||
panel_timeline->paste(false);
|
||||
}
|
||||
}
|
||||
@@ -646,6 +654,7 @@ void MainWindow::viewMenu_About_To_Be_Shown() {
|
||||
ui->actionFrames->setChecked(config.timecode_view == TIMECODE_FRAMES);
|
||||
ui->actionDrop_Frame->setChecked(config.timecode_view == TIMECODE_DROP);
|
||||
ui->actionNon_Drop_Frame->setChecked(config.timecode_view == TIMECODE_NONDROP);
|
||||
ui->actionMilliseconds->setChecked(config.timecode_view == TIMECODE_MILLISECONDS);
|
||||
|
||||
ui->actionOff->setChecked(!config.show_title_safe_area);
|
||||
ui->actionDefault->setChecked(config.show_title_safe_area && !config.use_custom_title_safe_ratio);
|
||||
@@ -1012,3 +1021,8 @@ void MainWindow::on_actionPage_Autoscroll_triggered() {
|
||||
void MainWindow::on_actionSmooth_Auto_scroll_triggered() {
|
||||
config.autoscroll = AUTOSCROLL_SMOOTH_SCROLL;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionMilliseconds_triggered() {
|
||||
config.timecode_view = TIMECODE_MILLISECONDS;
|
||||
update_ui(false);
|
||||
}
|
||||
|
||||
@@ -211,6 +211,8 @@ private slots:
|
||||
|
||||
void on_actionSmooth_Auto_scroll_triggered();
|
||||
|
||||
void on_actionMilliseconds_triggered();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
void setup_layout(bool reset);
|
||||
|
||||
+10
-1
@@ -33,7 +33,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>653</width>
|
||||
<height>19</height>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
@@ -144,6 +144,7 @@
|
||||
<addaction name="actionFrames"/>
|
||||
<addaction name="actionDrop_Frame"/>
|
||||
<addaction name="actionNon_Drop_Frame"/>
|
||||
<addaction name="actionMilliseconds"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuTitle_Action_Safe_Area"/>
|
||||
</widget>
|
||||
@@ -916,6 +917,14 @@
|
||||
<string>Smooth Auto-scroll</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMilliseconds">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Milliseconds</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
||||
@@ -89,7 +89,9 @@ SOURCES += \
|
||||
project/transition.cpp \
|
||||
project/effectrow.cpp \
|
||||
project/effectfield.cpp \
|
||||
effects/internal/cubetransition.cpp
|
||||
effects/internal/cubetransition.cpp \
|
||||
project/effectgizmo.cpp \
|
||||
io/clipboard.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
@@ -158,7 +160,9 @@ HEADERS += \
|
||||
project/transition.h \
|
||||
project/effectrow.h \
|
||||
project/effectfield.h \
|
||||
effects/internal/cubetransition.h
|
||||
effects/internal/cubetransition.h \
|
||||
project/effectgizmo.h \
|
||||
io/clipboard.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui \
|
||||
|
||||
+143
-179
@@ -17,6 +17,7 @@
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "ui/viewerwidget.h"
|
||||
#include "io/clipboard.h"
|
||||
#include "debug.h"
|
||||
|
||||
EffectControls::EffectControls(QWidget *parent) :
|
||||
@@ -24,7 +25,8 @@ EffectControls::EffectControls(QWidget *parent) :
|
||||
multiple(false),
|
||||
zoom(1),
|
||||
ui(new Ui::EffectControls),
|
||||
panel_name("Effects: ")
|
||||
panel_name("Effects: "),
|
||||
mode(TA_NO_TRANSITION)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@@ -64,14 +66,14 @@ void EffectControls::menu_select(QAction* q) {
|
||||
ComboAction* ca = new ComboAction();
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(selected_clips.at(i));
|
||||
if ((c->track < 0) == video_menu) {
|
||||
if ((c->track < 0) == (effect_menu_subtype == EFFECT_TYPE_VIDEO)) {
|
||||
const EffectMeta* meta = reinterpret_cast<const EffectMeta*>(q->data().value<quintptr>());
|
||||
if (transition_menu) {
|
||||
if (effect_menu_type == EFFECT_TYPE_TRANSITION) {
|
||||
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));
|
||||
@@ -79,7 +81,7 @@ void EffectControls::menu_select(QAction* q) {
|
||||
}
|
||||
}
|
||||
undo_stack.push(ca);
|
||||
if (transition_menu) {
|
||||
if (effect_menu_type == EFFECT_TYPE_TRANSITION) {
|
||||
update_ui(true);
|
||||
} else {
|
||||
reload_clips();
|
||||
@@ -93,155 +95,108 @@ void EffectControls::update_keyframes() {
|
||||
}
|
||||
|
||||
void EffectControls::delete_selected_keyframes() {
|
||||
ui->keyframeView->delete_selected_keyframes();
|
||||
ui->keyframeView->delete_selected_keyframes();
|
||||
}
|
||||
|
||||
void EffectControls::show_effect_menu(bool video, bool transitions) {
|
||||
void EffectControls::copy(bool del) {
|
||||
if (mode == TA_NO_TRANSITION) {
|
||||
bool cleared = false;
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
EffectDeleteCommand* del_com = (del) ? new EffectDeleteCommand() : NULL;
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(selected_clips.at(i));
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
Effect* effect = c->effects.at(j);
|
||||
if (effect->container->selected) {
|
||||
if (!cleared) {
|
||||
clipboard_type = CLIPBOARD_TYPE_EFFECT;
|
||||
clear_clipboard();
|
||||
cleared = true;
|
||||
}
|
||||
|
||||
/*video_menu = video;
|
||||
transition_menu = transitions;
|
||||
clipboard.append(effect->copy(NULL));
|
||||
|
||||
int lim;
|
||||
QVector<QString>* effect_names;
|
||||
if (transitions) {
|
||||
if (video) {
|
||||
lim = VIDEO_TRANSITION_COUNT;
|
||||
effect_names = &video_transition_names;
|
||||
} else {
|
||||
lim = AUDIO_TRANSITION_COUNT;
|
||||
effect_names = &audio_transition_names;
|
||||
}
|
||||
} else {
|
||||
if (video) {
|
||||
lim = VIDEO_EFFECT_COUNT;
|
||||
effect_names = &video_effect_names;
|
||||
} else {
|
||||
lim = AUDIO_EFFECT_COUNT;
|
||||
effect_names = &audio_effect_names;
|
||||
}
|
||||
}
|
||||
|
||||
QMenu effects_menu(this);
|
||||
|
||||
for (int i=0;i<lim;i++) {
|
||||
QAction* action = new QAction(&effects_menu);
|
||||
action->setText(effect_names->at(i));
|
||||
action->setData(i);
|
||||
|
||||
// sort alphabetically
|
||||
bool added = false;
|
||||
for (int j=0;j<effects_menu.actions().size();j++) {
|
||||
QAction* comp_action = effects_menu.actions().at(j);
|
||||
if (comp_action->text() > effect_names->at(i)) {
|
||||
effects_menu.insertAction(comp_action, action);
|
||||
added = true;
|
||||
break;
|
||||
if (del_com != NULL) {
|
||||
del_com->clips.append(c);
|
||||
del_com->fx.append(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!added) effects_menu.addAction(action);
|
||||
if (del_com != NULL) {
|
||||
if (del_com->clips.size() > 0) {
|
||||
ca->append(del_com);
|
||||
} else {
|
||||
delete del_com;
|
||||
}
|
||||
}
|
||||
undo_stack.push(ca);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectControls::show_effect_menu(int type, int subtype) {
|
||||
effect_menu_type = type;
|
||||
effect_menu_subtype = subtype;
|
||||
|
||||
effects_loaded.lock();
|
||||
|
||||
QMenu effects_menu(this);
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
const EffectMeta& em = effects.at(i);
|
||||
|
||||
if (em.type == type && em.subtype == subtype) {
|
||||
QAction* action = new QAction(&effects_menu);
|
||||
action->setText(em.name);
|
||||
action->setData(reinterpret_cast<quintptr>(&em));
|
||||
|
||||
QMenu* parent = &effects_menu;
|
||||
if (!em.category.isEmpty()) {
|
||||
bool found = false;
|
||||
for (int j=0;j<effects_menu.actions().size();j++) {
|
||||
QAction* action = effects_menu.actions().at(j);
|
||||
if (action->menu() != NULL) {
|
||||
if (action->menu()->title() == em.category) {
|
||||
parent = action->menu();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
parent = new QMenu(&effects_menu);
|
||||
parent->setTitle(em.category);
|
||||
|
||||
bool found = false;
|
||||
for (int i=0;i<effects_menu.actions().size();i++) {
|
||||
QAction* comp_action = effects_menu.actions().at(i);
|
||||
if (comp_action->text() > em.category) {
|
||||
effects_menu.insertMenu(comp_action, parent);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) effects_menu.addMenu(parent);
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (int i=0;i<parent->actions().size();i++) {
|
||||
QAction* comp_action = parent->actions().at(i);
|
||||
if (comp_action->text() > action->text()) {
|
||||
parent->insertAction(comp_action, action);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) parent->addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
effects_loaded.unlock();
|
||||
|
||||
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*)));
|
||||
|
||||
effects_menu.exec(QCursor::pos());*/
|
||||
|
||||
video_menu = video;
|
||||
transition_menu = transitions;
|
||||
|
||||
/*if (transition_menu) {
|
||||
// TODO old effect/transition code grandfathered in, to be updated
|
||||
|
||||
int lim;
|
||||
QVector<QString>* effect_names;
|
||||
if (video) {
|
||||
lim = VIDEO_TRANSITION_COUNT;
|
||||
effect_names = &video_transition_names;
|
||||
} else {
|
||||
lim = AUDIO_TRANSITION_COUNT;
|
||||
effect_names = &audio_transition_names;
|
||||
}
|
||||
QMenu effects_menu(this);
|
||||
for (int i=0;i<lim;i++) {
|
||||
QAction* action = new QAction(&effects_menu);
|
||||
action->setText(effect_names->at(i));
|
||||
action->setData(i);
|
||||
|
||||
// sort alphabetically
|
||||
bool added = false;
|
||||
for (int j=0;j<effects_menu.actions().size();j++) {
|
||||
QAction* comp_action = effects_menu.actions().at(j);
|
||||
if (comp_action->text() > effect_names->at(i)) {
|
||||
effects_menu.insertAction(comp_action, action);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!added) effects_menu.addAction(action);
|
||||
}
|
||||
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*)));
|
||||
effects_menu.exec(QCursor::pos());
|
||||
} else {*/
|
||||
effects_loaded.lock();
|
||||
|
||||
QVector<EffectMeta>& effect_list = (video) ? video_effects : audio_effects;
|
||||
QMenu effects_menu(this);
|
||||
for (int i=0;i<effect_list.size();i++) {
|
||||
const EffectMeta& em = effect_list.at(i);
|
||||
|
||||
if ((em.type == EFFECT_TYPE_TRANSITION) == transition_menu) {
|
||||
QAction* action = new QAction(&effects_menu);
|
||||
action->setText(em.name);
|
||||
action->setData(reinterpret_cast<quintptr>(&em));
|
||||
|
||||
QMenu* parent = &effects_menu;
|
||||
if (!em.category.isEmpty()) {
|
||||
bool found = false;
|
||||
for (int j=0;j<effects_menu.actions().size();j++) {
|
||||
QAction* action = effects_menu.actions().at(j);
|
||||
if (action->menu() != NULL) {
|
||||
if (action->menu()->title() == em.category) {
|
||||
parent = action->menu();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
parent = new QMenu(&effects_menu);
|
||||
parent->setTitle(em.category);
|
||||
|
||||
bool found = false;
|
||||
for (int i=0;i<effects_menu.actions().size();i++) {
|
||||
QAction* comp_action = effects_menu.actions().at(i);
|
||||
if (comp_action->text() > em.category) {
|
||||
effects_menu.insertMenu(comp_action, parent);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) effects_menu.addMenu(parent);
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (int i=0;i<parent->actions().size();i++) {
|
||||
QAction* comp_action = parent->actions().at(i);
|
||||
if (comp_action->text() > action->text()) {
|
||||
parent->insertAction(comp_action, action);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) parent->addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
effects_loaded.unlock();
|
||||
|
||||
connect(&effects_menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_select(QAction*)));
|
||||
effects_menu.exec(QCursor::pos());
|
||||
//}
|
||||
effects_menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void EffectControls::clear_effects(bool clear_cache) {
|
||||
@@ -275,12 +230,19 @@ void EffectControls::deselect_all_effects(QWidget* sender) {
|
||||
}
|
||||
}
|
||||
}
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
}
|
||||
|
||||
void EffectControls::open_effect(QVBoxLayout* layout, Effect* e) {
|
||||
CollapsibleWidget* container = e->container;
|
||||
layout->addWidget(container);
|
||||
connect(container, SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*)));
|
||||
}
|
||||
|
||||
void EffectControls::load_effects() {
|
||||
ui->label_2->setVisible(multiple);
|
||||
|
||||
if (!multiple) {
|
||||
if (!multiple) {
|
||||
// load in new clips
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(selected_clips.at(i));
|
||||
@@ -292,12 +254,15 @@ void EffectControls::load_effects() {
|
||||
ui->acontainer->setVisible(true);
|
||||
layout = static_cast<QVBoxLayout*>(ui->audio_effect_area->layout());
|
||||
}
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
Effect* e = c->effects.at(j);
|
||||
CollapsibleWidget* container = e->container;
|
||||
layout->addWidget(container);
|
||||
connect(container, SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*)));
|
||||
}
|
||||
if (mode == TA_NO_TRANSITION) {
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
open_effect(layout, c->effects.at(j));
|
||||
}
|
||||
} else if (mode == TA_OPENING_TRANSITION && c->get_opening_transition() != NULL) {
|
||||
open_effect(layout, c->get_opening_transition());
|
||||
} else if (mode == TA_CLOSING_TRANSITION && c->get_closing_transition() != NULL) {
|
||||
open_effect(layout, c->get_closing_transition());
|
||||
}
|
||||
}
|
||||
if (selected_clips.size() > 0) {
|
||||
setWindowTitle(panel_name + sequence->clips.at(selected_clips.at(0))->name);
|
||||
@@ -311,22 +276,24 @@ void EffectControls::load_effects() {
|
||||
|
||||
void EffectControls::delete_effects() {
|
||||
// load in new clips
|
||||
EffectDeleteCommand* command = new EffectDeleteCommand();
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(selected_clips.at(i));
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
Effect* effect = c->effects.at(j);
|
||||
if (effect->container->selected) {
|
||||
command->clips.append(c);
|
||||
command->fx.append(j);
|
||||
if (mode == TA_NO_TRANSITION) {
|
||||
EffectDeleteCommand* command = new EffectDeleteCommand();
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(selected_clips.at(i));
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
Effect* effect = c->effects.at(j);
|
||||
if (effect->container->selected) {
|
||||
command->clips.append(c);
|
||||
command->fx.append(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (command->clips.size() > 0) {
|
||||
undo_stack.push(command);
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
} else {
|
||||
delete command;
|
||||
if (command->clips.size() > 0) {
|
||||
undo_stack.push(command);
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
} else {
|
||||
delete command;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,33 +302,30 @@ void EffectControls::reload_clips() {
|
||||
load_effects();
|
||||
}
|
||||
|
||||
void EffectControls::set_clips(QVector<int>& clips) {
|
||||
void EffectControls::set_clips(QVector<int>& clips, int m) {
|
||||
clear_effects(true);
|
||||
|
||||
// replace clip vector
|
||||
selected_clips = clips;
|
||||
mode = m;
|
||||
|
||||
load_effects();
|
||||
}
|
||||
|
||||
void EffectControls::on_add_video_effect_button_clicked()
|
||||
{
|
||||
show_effect_menu(true, false);
|
||||
void EffectControls::on_add_video_effect_button_clicked() {
|
||||
show_effect_menu(EFFECT_TYPE_EFFECT, EFFECT_TYPE_VIDEO);
|
||||
}
|
||||
|
||||
void EffectControls::on_add_audio_effect_button_clicked()
|
||||
{
|
||||
show_effect_menu(false, false);
|
||||
void EffectControls::on_add_audio_effect_button_clicked() {
|
||||
show_effect_menu(EFFECT_TYPE_EFFECT, EFFECT_TYPE_AUDIO);
|
||||
}
|
||||
|
||||
void EffectControls::on_add_video_transition_button_clicked()
|
||||
{
|
||||
show_effect_menu(true, true);
|
||||
void EffectControls::on_add_video_transition_button_clicked() {
|
||||
show_effect_menu(EFFECT_TYPE_TRANSITION, EFFECT_TYPE_VIDEO);
|
||||
}
|
||||
|
||||
void EffectControls::on_add_audio_transition_button_clicked()
|
||||
{
|
||||
show_effect_menu(false, true);
|
||||
void EffectControls::on_add_audio_transition_button_clicked() {
|
||||
show_effect_menu(EFFECT_TYPE_TRANSITION, EFFECT_TYPE_AUDIO);
|
||||
}
|
||||
|
||||
void EffectControls::resizeEvent(QResizeEvent*) {
|
||||
|
||||
@@ -10,6 +10,7 @@ class Effect;
|
||||
class TimelineHeader;
|
||||
class QScrollArea;
|
||||
class KeyframeView;
|
||||
class QVBoxLayout;
|
||||
|
||||
class EffectsArea : public QWidget {
|
||||
public:
|
||||
@@ -31,7 +32,7 @@ class EffectControls : public QDockWidget
|
||||
public:
|
||||
explicit EffectControls(QWidget *parent = 0);
|
||||
~EffectControls();
|
||||
void set_clips(QVector<int>& clips);
|
||||
void set_clips(QVector<int>& clips, int mode);
|
||||
void clear_effects(bool clear_cache);
|
||||
void delete_effects();
|
||||
bool is_focused();
|
||||
@@ -39,6 +40,7 @@ public:
|
||||
void set_zoom(bool in);
|
||||
bool keyframe_focus();
|
||||
void delete_selected_keyframes();
|
||||
void copy(bool del);
|
||||
bool multiple;
|
||||
|
||||
QVector<int> selected_clips;
|
||||
@@ -55,18 +57,19 @@ private slots:
|
||||
void deselect_all_effects(QWidget*);
|
||||
|
||||
void on_add_video_transition_button_clicked();
|
||||
|
||||
void on_add_audio_transition_button_clicked();
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
private:
|
||||
void show_effect_menu(bool video, bool transitions);
|
||||
void show_effect_menu(int type, int subtype);
|
||||
void load_effects();
|
||||
void load_keyframes();
|
||||
void open_effect(QVBoxLayout* layout, Effect* e);
|
||||
|
||||
bool video_menu;
|
||||
bool transition_menu;
|
||||
int effect_menu_type;
|
||||
int effect_menu_subtype;
|
||||
QString panel_name;
|
||||
int mode;
|
||||
};
|
||||
|
||||
#endif // EFFECTCONTROLS_H
|
||||
|
||||
+51
-16
@@ -5,6 +5,8 @@
|
||||
#include "viewer.h"
|
||||
#include "project/sequence.h"
|
||||
#include "project/clip.h"
|
||||
#include "project/transition.h"
|
||||
#include "debug.h"
|
||||
|
||||
Project* panel_project = 0;
|
||||
EffectControls* panel_effect_controls = 0;
|
||||
@@ -17,28 +19,47 @@ void update_effect_controls() {
|
||||
// find out how many clips are selected
|
||||
// limits to one video clip and one audio clip and only if they're linked
|
||||
// one of these days it might be nice to have multiple clips in the effects panel
|
||||
panel_effect_controls->multiple = false;
|
||||
bool multiple = false;
|
||||
int vclip = -1;
|
||||
int aclip = -1;
|
||||
QVector<int> selected_clips;
|
||||
int mode = TA_NO_TRANSITION;
|
||||
if (sequence != NULL) {
|
||||
for (int i=0;i<sequence->clips.size();i++) {
|
||||
Clip* clip = sequence->clips.at(i);
|
||||
if (clip != NULL && panel_timeline->is_clip_selected(clip, true)) {
|
||||
if (clip->track < 0 && vclip == -1) {
|
||||
vclip = i;
|
||||
} else if (clip->track >= 0 && aclip == -1) {
|
||||
aclip = i;
|
||||
} else {
|
||||
vclip = -2;
|
||||
aclip = -2;
|
||||
panel_effect_controls->multiple = true;
|
||||
break;
|
||||
}
|
||||
if (clip != NULL) {
|
||||
for (int j=0;j<sequence->selections.size();j++) {
|
||||
const Selection& s = sequence->selections.at(j);
|
||||
bool add = true;
|
||||
if (clip->timeline_in >= s.in && clip->timeline_out <= s.out && clip->track == s.track) {
|
||||
mode = TA_NO_TRANSITION;
|
||||
} else if (selection_contains_transition(s, clip, TA_OPENING_TRANSITION)) {
|
||||
mode = TA_OPENING_TRANSITION;
|
||||
} else if (selection_contains_transition(s, clip, TA_CLOSING_TRANSITION)) {
|
||||
mode = TA_CLOSING_TRANSITION;
|
||||
} else {
|
||||
add = false;
|
||||
}
|
||||
|
||||
if (add) {
|
||||
if (clip->track < 0 && vclip == -1) {
|
||||
vclip = i;
|
||||
} else if (clip->track >= 0 && aclip == -1) {
|
||||
aclip = i;
|
||||
} else {
|
||||
vclip = -2;
|
||||
aclip = -2;
|
||||
multiple = true;
|
||||
multiple = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if aclip is linked to vclip
|
||||
if (!panel_effect_controls->multiple) {
|
||||
|
||||
if (!multiple) {
|
||||
// check if aclip is linked to vclip
|
||||
if (vclip >= 0) selected_clips.append(vclip);
|
||||
if (aclip >= 0) selected_clips.append(aclip);
|
||||
if (vclip >= 0 && aclip >= 0) {
|
||||
@@ -53,12 +74,26 @@ void update_effect_controls() {
|
||||
if (!found) {
|
||||
// only display multiple clips if they're linked
|
||||
selected_clips.clear();
|
||||
panel_effect_controls->multiple = true;
|
||||
multiple = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
panel_effect_controls->set_clips(selected_clips);
|
||||
|
||||
bool same = (selected_clips.size() == panel_effect_controls->selected_clips.size());
|
||||
if (same) {
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
if (selected_clips.at(i) != panel_effect_controls->selected_clips.at(i)) {
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (panel_effect_controls->multiple != multiple || !same) {
|
||||
panel_effect_controls->multiple = multiple;
|
||||
panel_effect_controls->set_clips(selected_clips, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void update_ui(bool modified) {
|
||||
|
||||
+188
-106
@@ -21,6 +21,7 @@
|
||||
#include "dialogs/newsequencedialog.h"
|
||||
#include "dialogs/mediapropertiesdialog.h"
|
||||
#include "dialogs/loaddialog.h"
|
||||
#include "io/clipboard.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
@@ -317,15 +318,17 @@ void Project::get_all_media_from_table(QList<QTreeWidgetItem*> items, QList<QTre
|
||||
}
|
||||
|
||||
bool delete_clips_in_clipboard_with_media(ComboAction* ca, Media* m) {
|
||||
int delete_count = 0;
|
||||
for (int i=0;i<panel_timeline->clip_clipboard.size();i++) {
|
||||
Clip* c = panel_timeline->clip_clipboard.at(i);
|
||||
if (c->media == m) {
|
||||
ca->append(new RemoveClipsFromClipboard(i-delete_count));
|
||||
delete_count++;
|
||||
}
|
||||
}
|
||||
return (delete_count > 0);
|
||||
int delete_count = 0;
|
||||
if (clipboard_type == CLIPBOARD_TYPE_CLIP) {
|
||||
for (int i=0;i<clipboard.size();i++) {
|
||||
Clip* c = static_cast<Clip*>(clipboard.at(i));
|
||||
if (c->media == m) {
|
||||
ca->append(new RemoveClipsFromClipboard(i-delete_count));
|
||||
delete_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (delete_count > 0);
|
||||
}
|
||||
|
||||
void Project::delete_selected_media() {
|
||||
@@ -808,6 +811,100 @@ QTreeWidgetItem* Project::find_loaded_folder_by_id(int id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EffectMeta* get_meta_from_name(const QString& name, int type) {
|
||||
for (int j=0;j<effects.size();j++) {
|
||||
if (effects.at(j).name == name) {
|
||||
return &effects.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->set_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 +1065,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 +1081,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 +1141,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 +1190,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 +1201,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 +1223,46 @@ 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 || secondary != NULL) {
|
||||
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)->set_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 +1494,18 @@ 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));
|
||||
stream.writeAttribute("length", QString::number(t->get_true_length()));
|
||||
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 +1517,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 +1552,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
|
||||
}
|
||||
|
||||
+148
-83
@@ -18,6 +18,7 @@
|
||||
#include "project/effect.h"
|
||||
#include "project/transition.h"
|
||||
#include "io/media.h"
|
||||
#include "io/clipboard.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <QTime>
|
||||
@@ -45,6 +46,7 @@ Timeline::Timeline(QWidget *parent) :
|
||||
cursor_frame(0),
|
||||
cursor_track(0),
|
||||
zoom(1.0),
|
||||
zoom_just_changed(false),
|
||||
showing_all(false),
|
||||
snapping(true),
|
||||
snapped(false),
|
||||
@@ -324,11 +326,11 @@ void Timeline::add_clips_from_ghosts(ComboAction* ca, Sequence* s) {
|
||||
|
||||
if (c->track < 0) {
|
||||
// add default video effects
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TRANSFORM)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT)));
|
||||
} else {
|
||||
// add default audio effects
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_VOLUME)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_PAN)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT)));
|
||||
}
|
||||
}
|
||||
if (config.enable_seek_to_import) {
|
||||
@@ -355,11 +357,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, EFFECT_TYPE_TRANSITION), 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, EFFECT_TYPE_TRANSITION), TA_OPENING_TRANSITION, 30));
|
||||
adding = true;
|
||||
}
|
||||
}
|
||||
@@ -430,7 +432,8 @@ void Timeline::repaint_timeline() {
|
||||
|
||||
if (sequence != NULL
|
||||
&& !ui->horizontalScrollBar->isSliderDown()
|
||||
&& panel_sequence_viewer->playing) {
|
||||
&& panel_sequence_viewer->playing
|
||||
&& !zoom_just_changed) {
|
||||
// auto scroll
|
||||
if (config.autoscroll == AUTOSCROLL_PAGE_SCROLL) {
|
||||
int playhead_x = panel_timeline->getTimelineScreenPointFromFrame(sequence->playhead);
|
||||
@@ -445,6 +448,8 @@ void Timeline::repaint_timeline() {
|
||||
}
|
||||
}
|
||||
|
||||
zoom_just_changed = false;
|
||||
|
||||
if (draw) {
|
||||
ui->headers->update();
|
||||
ui->video_area->update();
|
||||
@@ -568,8 +573,10 @@ void Timeline::delete_selection(QVector<Selection>& selections, bool ripple_dele
|
||||
|
||||
void Timeline::set_zoom_value(double v) {
|
||||
zoom = v;
|
||||
ui->headers->update_zoom(zoom);
|
||||
repaint_timeline();
|
||||
zoom_just_changed = true;
|
||||
ui->headers->update_zoom(zoom);
|
||||
|
||||
repaint_timeline();
|
||||
|
||||
// TODO find a way to gradually move towards target_scroll instead of just centering it?
|
||||
center_scroll_to_playhead();
|
||||
@@ -634,10 +641,16 @@ 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 (pre->get_opening_transition()->length > new_clip_length) {
|
||||
/*if (frame < pre->timeline_in + pre->get_opening_transition()->length && pre->get_opening_transition()->secondary_clip != NULL) {
|
||||
// separate shared transition
|
||||
ca->append(new SetPointer((void**) &pre->get_opening_transition()->secondary_clip, NULL));
|
||||
pre->get_opening_transition()->secondary_clip->closing_transition = pre->get_opening_transition()->copy(pre->get_opening_transition()->secondary_clip, NULL);
|
||||
}*/
|
||||
|
||||
if (pre->get_opening_transition()->get_true_length() > new_clip_length) {
|
||||
ca->append(new ModifyTransitionCommand(pre, TA_OPENING_TRANSITION, new_clip_length));
|
||||
}
|
||||
|
||||
@@ -645,8 +658,7 @@ Clip* Timeline::split_clip(ComboAction* ca, int p, long frame, long post_in) {
|
||||
}
|
||||
if (pre->get_closing_transition() != NULL) {
|
||||
ca->append(new DeleteTransitionCommand(pre, TA_CLOSING_TRANSITION));
|
||||
|
||||
post->get_closing_transition()->length = qMin((long) post->get_closing_transition()->length, post->getLength());
|
||||
if (pre->get_closing_transition()->secondary_clip == NULL) post->get_closing_transition()->set_length(qMin((long) post->get_closing_transition()->get_true_length(), post->getLength()));
|
||||
}
|
||||
|
||||
return post;
|
||||
@@ -743,6 +755,20 @@ void Timeline::clean_up_selections(QVector<Selection>& areas) {
|
||||
}
|
||||
}
|
||||
|
||||
bool selection_contains_transition(const Selection& s, Clip* c, int type) {
|
||||
if (type == TA_OPENING_TRANSITION) {
|
||||
return c->get_opening_transition() != NULL
|
||||
&& s.out == c->timeline_in + c->get_opening_transition()->get_true_length()
|
||||
&& ((c->get_opening_transition()->secondary_clip == NULL && s.in == c->timeline_in)
|
||||
|| (c->get_opening_transition()->secondary_clip != NULL && s.in == c->timeline_in - c->get_opening_transition()->get_true_length()));
|
||||
} else {
|
||||
return c->get_closing_transition() != NULL
|
||||
&& s.in == c->timeline_out - c->get_closing_transition()->get_true_length()
|
||||
&& ((c->get_closing_transition()->secondary_clip == NULL && s.out == c->timeline_out)
|
||||
|| (c->get_closing_transition()->secondary_clip != NULL && s.out == c->timeline_out + c->get_closing_transition()->get_true_length()));
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::delete_areas_and_relink(ComboAction* ca, QVector<Selection>& areas) {
|
||||
clean_up_selections(areas);
|
||||
|
||||
@@ -754,14 +780,10 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector<Selection>& area
|
||||
for (int j=0;j<sequence->clips.size();j++) {
|
||||
Clip* c = sequence->clips.at(j);
|
||||
if (c != NULL && c->track == s.track && !c->undeletable) {
|
||||
if (c->get_opening_transition() != NULL
|
||||
&& s.in == c->timeline_in
|
||||
&& s.out == c->timeline_in + c->get_opening_transition()->length) {
|
||||
if (selection_contains_transition(s, c, TA_OPENING_TRANSITION)) {
|
||||
// delete opening transition
|
||||
ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION));
|
||||
} else if (c->get_closing_transition() != NULL
|
||||
&& s.out == c->timeline_out
|
||||
&& s.in == c->timeline_out - c->get_closing_transition()->length) {
|
||||
} else if (selection_contains_transition(s, c, TA_CLOSING_TRANSITION)) {
|
||||
// delete closing transition
|
||||
ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION));
|
||||
} else if (c->timeline_in >= s.in && c->timeline_out <= s.out) {
|
||||
@@ -777,24 +799,24 @@ 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) {
|
||||
if (s.in < c->timeline_out - c->get_closing_transition()->get_true_length()) {
|
||||
ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION));
|
||||
} else {
|
||||
ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, c->get_closing_transition()->length - (c->timeline_out - s.in)));
|
||||
ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, c->get_closing_transition()->get_true_length() - (c->timeline_out - s.in)));
|
||||
}
|
||||
}
|
||||
} else if (c->timeline_in < s.out && c->timeline_out > s.out) {
|
||||
// only in point is in deletion area
|
||||
ca->append(new MoveClipAction(c, s.out, c->timeline_out, c->clip_in + (s.out - c->timeline_in), c->track));
|
||||
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) {
|
||||
if (s.out > c->timeline_in + c->get_opening_transition()->get_true_length()) {
|
||||
ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION));
|
||||
} else {
|
||||
ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, c->get_opening_transition()->length - (s.out - c->timeline_in)));
|
||||
ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, c->get_opening_transition()->get_true_length() - (s.out - c->timeline_in)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -818,12 +840,15 @@ void Timeline::copy(bool del) {
|
||||
const Selection& s = sequence->selections.at(j);
|
||||
if (s.track == c->track && !((c->timeline_in <= s.in && c->timeline_out <= s.in) || (c->timeline_in >= s.out && c->timeline_out >= s.out))) {
|
||||
if (!cleared) {
|
||||
clip_clipboard.clear();
|
||||
clear_clipboard();
|
||||
cleared = true;
|
||||
clipboard_type = CLIPBOARD_TYPE_CLIP;
|
||||
}
|
||||
|
||||
Clip* copied_clip = c->copy(NULL);
|
||||
|
||||
copied_clip->cached_fr = sequence->frame_rate;
|
||||
|
||||
// copy linked IDs (we correct these later in paste())
|
||||
copied_clip->linked = c->linked;
|
||||
|
||||
@@ -845,16 +870,16 @@ void Timeline::copy(bool del) {
|
||||
|
||||
copied_clip->load_id = i;
|
||||
|
||||
clip_clipboard.append(copied_clip);
|
||||
clipboard.append(copied_clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<clip_clipboard.size();i++) {
|
||||
for (int i=0;i<clipboard.size();i++) {
|
||||
// initialize all timeline_ins to 0 or offsets of
|
||||
clip_clipboard[i]->timeline_in -= min_in;
|
||||
clip_clipboard[i]->timeline_out -= min_in;
|
||||
static_cast<Clip*>(clipboard.at(i))->timeline_in -= min_in;
|
||||
static_cast<Clip*>(clipboard.at(i))->timeline_out -= min_in;
|
||||
}
|
||||
|
||||
if (del && copied) {
|
||||
@@ -878,66 +903,88 @@ void Timeline::relink_clips_using_ids(QVector<int>& old_clips, QVector<Clip*>& n
|
||||
}
|
||||
|
||||
void Timeline::paste(bool insert) {
|
||||
if (clip_clipboard.size() > 0) {
|
||||
ComboAction* ca = new ComboAction();
|
||||
if (clipboard.size() > 0) {
|
||||
if (clipboard_type == CLIPBOARD_TYPE_CLIP) {
|
||||
ComboAction* ca = new ComboAction();
|
||||
|
||||
// create copies and delete areas that we'll be pasting to
|
||||
QVector<Selection> delete_areas;
|
||||
QVector<Clip*> pasted_clips;
|
||||
long paste_start = LONG_MAX;
|
||||
long paste_end = LONG_MIN;
|
||||
for (int i=0;i<clip_clipboard.size();i++) {
|
||||
Clip* c = clip_clipboard.at(i);
|
||||
// create copies and delete areas that we'll be pasting to
|
||||
QVector<Selection> delete_areas;
|
||||
QVector<Clip*> pasted_clips;
|
||||
long paste_start = LONG_MAX;
|
||||
long paste_end = LONG_MIN;
|
||||
for (int i=0;i<clipboard.size();i++) {
|
||||
Clip* c = static_cast<Clip*>(clipboard.at(i));
|
||||
|
||||
// create copy of clip and offset by playhead
|
||||
Clip* cc = c->copy(sequence);
|
||||
cc->timeline_in += sequence->playhead;
|
||||
cc->timeline_out += sequence->playhead;
|
||||
cc->track = c->track;
|
||||
// create copy of clip and offset by playhead
|
||||
Clip* cc = c->copy(sequence);
|
||||
|
||||
paste_start = qMin(paste_start, cc->timeline_in);
|
||||
paste_end = qMax(paste_end, cc->timeline_out);
|
||||
// convert frame rates
|
||||
cc->timeline_in = refactor_frame_number(cc->timeline_in, c->cached_fr, sequence->frame_rate);
|
||||
cc->timeline_out = refactor_frame_number(cc->timeline_out, c->cached_fr, sequence->frame_rate);
|
||||
cc->clip_in = refactor_frame_number(cc->clip_in, c->cached_fr, sequence->frame_rate);
|
||||
|
||||
pasted_clips.append(cc);
|
||||
cc->timeline_in += sequence->playhead;
|
||||
cc->timeline_out += sequence->playhead;
|
||||
cc->track = c->track;
|
||||
|
||||
if (!insert) {
|
||||
Selection s;
|
||||
s.in = cc->timeline_in;
|
||||
s.out = cc->timeline_out;
|
||||
s.track = c->track;
|
||||
delete_areas.append(s);
|
||||
paste_start = qMin(paste_start, cc->timeline_in);
|
||||
paste_end = qMax(paste_end, cc->timeline_out);
|
||||
|
||||
pasted_clips.append(cc);
|
||||
|
||||
if (!insert) {
|
||||
Selection s;
|
||||
s.in = cc->timeline_in;
|
||||
s.out = cc->timeline_out;
|
||||
s.track = c->track;
|
||||
delete_areas.append(s);
|
||||
}
|
||||
}
|
||||
if (insert) {
|
||||
split_cache.clear();
|
||||
split_all_clips_at_point(ca, sequence->playhead);
|
||||
ca->append(new RippleCommand(sequence, paste_start, paste_end - paste_start));
|
||||
} else {
|
||||
delete_areas_and_relink(ca, delete_areas);
|
||||
}
|
||||
}
|
||||
if (insert) {
|
||||
split_cache.clear();
|
||||
split_all_clips_at_point(ca, sequence->playhead);
|
||||
ca->append(new RippleCommand(sequence, paste_start, paste_end - paste_start));
|
||||
} else {
|
||||
delete_areas_and_relink(ca, delete_areas);
|
||||
}
|
||||
|
||||
// correct linked clips
|
||||
for (int i=0;i<clip_clipboard.size();i++) {
|
||||
// these indices should correspond
|
||||
Clip* oc = clip_clipboard.at(i);
|
||||
// correct linked clips
|
||||
for (int i=0;i<clipboard.size();i++) {
|
||||
// these indices should correspond
|
||||
Clip* oc = static_cast<Clip*>(clipboard.at(i));
|
||||
|
||||
for (int j=0;j<oc->linked.size();j++) {
|
||||
for (int k=0;k<clip_clipboard.size();k++) { // find clip with that ID
|
||||
if (clip_clipboard.at(k)->load_id == oc->linked.at(j)) {
|
||||
pasted_clips.at(i)->linked.append(k);
|
||||
for (int j=0;j<oc->linked.size();j++) {
|
||||
for (int k=0;k<clipboard.size();k++) { // find clip with that ID
|
||||
Clip* comp = static_cast<Clip*>(clipboard.at(k));
|
||||
if (comp->load_id == oc->linked.at(j)) {
|
||||
pasted_clips.at(i)->linked.append(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ca->append(new AddClipCommand(sequence, pasted_clips));
|
||||
ca->append(new AddClipCommand(sequence, pasted_clips));
|
||||
|
||||
undo_stack.push(ca);
|
||||
undo_stack.push(ca);
|
||||
|
||||
update_ui(true);
|
||||
update_ui(true);
|
||||
|
||||
if (config.paste_seeks) {
|
||||
panel_sequence_viewer->seek(paste_end);
|
||||
if (config.paste_seeks) {
|
||||
panel_sequence_viewer->seek(paste_end);
|
||||
}
|
||||
} else if (clipboard_type == CLIPBOARD_TYPE_EFFECT) {
|
||||
for (int i=0;i<sequence->clips.size();i++) {
|
||||
Clip* c = sequence->clips.at(i);
|
||||
if (c != NULL && is_clip_selected(c, true)) {
|
||||
for (int j=0;j<clipboard.size();j++) {
|
||||
Effect* e = static_cast<Effect*>(clipboard.at(j));
|
||||
if ((c->track < 0) == (e->meta->subtype == EFFECT_TYPE_VIDEO)) {
|
||||
c->effects.append(e->copy(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
update_ui(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1060,7 +1107,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);
|
||||
@@ -1226,10 +1273,10 @@ bool Timeline::snap_to_timeline(long* l, bool use_playhead, bool use_markers, bo
|
||||
} else if (snap_to_point(c->timeline_out, l)) {
|
||||
return true;
|
||||
} else if (c->get_opening_transition() != NULL
|
||||
&& snap_to_point(c->timeline_in + c->get_opening_transition()->length, l)) {
|
||||
&& snap_to_point(c->timeline_in + c->get_opening_transition()->get_true_length(), l)) {
|
||||
return true;
|
||||
} else if (c->get_closing_transition() != NULL
|
||||
&& snap_to_point(c->timeline_out - c->get_closing_transition()->length, l)) {
|
||||
&& snap_to_point(c->timeline_out - c->get_closing_transition()->get_true_length(), l)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1433,9 +1480,9 @@ void Timeline::on_toolTransitionButton_clicked() {
|
||||
|
||||
QMenu transition_menu(this);
|
||||
|
||||
for (int i=0;i<video_effects.size();i++) {
|
||||
const EffectMeta& em = video_effects.at(i);
|
||||
if (em.type == EFFECT_TYPE_TRANSITION) {
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
const EffectMeta& em = effects.at(i);
|
||||
if (em.type == EFFECT_TYPE_TRANSITION && em.subtype == EFFECT_TYPE_VIDEO) {
|
||||
QAction* a = transition_menu.addAction(em.name);
|
||||
a->setObjectName("v");
|
||||
a->setData(reinterpret_cast<quintptr>(&em));
|
||||
@@ -1444,9 +1491,9 @@ void Timeline::on_toolTransitionButton_clicked() {
|
||||
|
||||
transition_menu.addSeparator();
|
||||
|
||||
for (int i=0;i<audio_effects.size();i++) {
|
||||
const EffectMeta& em = audio_effects.at(i);
|
||||
if (em.type == EFFECT_TYPE_TRANSITION) {
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
const EffectMeta& em = effects.at(i);
|
||||
if (em.type == EFFECT_TYPE_TRANSITION && em.subtype == EFFECT_TYPE_AUDIO) {
|
||||
QAction* a = transition_menu.addAction(em.name);
|
||||
a->setObjectName("a");
|
||||
a->setData(reinterpret_cast<quintptr>(&em));
|
||||
@@ -1474,3 +1521,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -33,6 +33,8 @@ long refactor_frame_number(long framenumber, double source_frame_rate, double ta
|
||||
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;
|
||||
@@ -118,6 +120,7 @@ public:
|
||||
long cursor_frame;
|
||||
int cursor_track;
|
||||
double zoom;
|
||||
bool zoom_just_changed;
|
||||
long drag_frame_start;
|
||||
int drag_track_start;
|
||||
void update_effect_controls();
|
||||
@@ -182,9 +185,6 @@ public:
|
||||
const EffectMeta* transition_tool_meta;
|
||||
int transition_tool_side;
|
||||
|
||||
// clipboard
|
||||
QVector<Clip*> clip_clipboard;
|
||||
|
||||
Ui::Timeline *ui;
|
||||
public slots:
|
||||
void repaint_timeline();
|
||||
|
||||
+29
-8
@@ -108,19 +108,37 @@ void Viewer::assert_audio_device() {
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate) {
|
||||
QList<QString> list = s.split(QRegExp("[:;]"));
|
||||
|
||||
if (view == TIMECODE_FRAMES || list.size() == 1) {
|
||||
if (view == TIMECODE_FRAMES || (list.size() == 1 && view != TIMECODE_MILLISECONDS)) {
|
||||
return s.toLong();
|
||||
}
|
||||
|
||||
int frRound = qRound(frame_rate);
|
||||
int hours = ((list.size() > 0) ? list.at(0).toInt() : 0) * frRound * 3600;
|
||||
int minutes = ((list.size() > 1) ? list.at(1).toInt() : 0) * frRound * 60;
|
||||
int seconds = ((list.size() > 2) ? list.at(2).toInt() : 0) * frRound;
|
||||
int frames = (list.size() > 3) ? list.at(3).toInt() : 0;
|
||||
int hours, minutes, seconds, frames;
|
||||
|
||||
if (view == TIMECODE_MILLISECONDS) {
|
||||
long milliseconds = s.toLong();
|
||||
|
||||
hours = milliseconds/3600000;
|
||||
milliseconds -= (hours*3600000);
|
||||
minutes = milliseconds/60000;
|
||||
milliseconds -= (minutes*60000);
|
||||
seconds = milliseconds/1000;
|
||||
milliseconds -= (seconds*1000);
|
||||
frames = qRound64((milliseconds*0.001)*frame_rate);
|
||||
|
||||
seconds = qRound64(seconds * frame_rate);
|
||||
minutes = qRound64(minutes * frame_rate * 60);
|
||||
hours = qRound64(hours * frame_rate * 3600);
|
||||
} else {
|
||||
hours = ((list.size() > 0) ? list.at(0).toInt() : 0) * frRound * 3600;
|
||||
minutes = ((list.size() > 1) ? list.at(1).toInt() : 0) * frRound * 60;
|
||||
seconds = ((list.size() > 2) ? list.at(2).toInt() : 0) * frRound;
|
||||
frames = (list.size() > 3) ? list.at(3).toInt() : 0;
|
||||
}
|
||||
|
||||
int f = (frames + seconds + minutes + hours);
|
||||
|
||||
if (view == TIMECODE_DROP && frame_rate_is_droppable(frame_rate)) {
|
||||
if ((view == TIMECODE_DROP || view == TIMECODE_MILLISECONDS) && frame_rate_is_droppable(frame_rate)) {
|
||||
// return drop
|
||||
int d;
|
||||
int m;
|
||||
@@ -155,7 +173,7 @@ QString frame_to_timecode(long f, int view, double frame_rate) {
|
||||
int frames = 0;
|
||||
QString token = ":";
|
||||
|
||||
if (view == TIMECODE_DROP && frame_rate_is_droppable(frame_rate)) {
|
||||
if ((view == TIMECODE_DROP || view == TIMECODE_MILLISECONDS) && frame_rate_is_droppable(frame_rate)) {
|
||||
//CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
|
||||
//Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team
|
||||
//Given an int called framenumber and a double called framerate
|
||||
@@ -165,7 +183,7 @@ QString frame_to_timecode(long f, int view, double frame_rate) {
|
||||
int m;
|
||||
|
||||
int dropFrames = round(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int framesPerHour = round(frame_rate*60*60); //Number of frames in an hour
|
||||
int framesPerHour = round(frame_rate*60*60); //Number of frqRound64ames in an hour
|
||||
int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours
|
||||
int framesPer10Minutes = round(frame_rate * 60 * 10); //Number of frames per ten minutes
|
||||
int framesPerMinute = (round(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
|
||||
@@ -199,6 +217,9 @@ QString frame_to_timecode(long f, int view, double frame_rate) {
|
||||
secs = f/int_fps % 60;
|
||||
frames = f%int_fps;
|
||||
}
|
||||
if (view == TIMECODE_MILLISECONDS) {
|
||||
return QString::number((hours*3600000)+(mins*60000)+(secs*1000)+qCeil(frames*1000/frame_rate));
|
||||
}
|
||||
return QString(QString::number(hours).rightJustified(2, '0') +
|
||||
":" + QString::number(mins).rightJustified(2, '0') +
|
||||
":" + QString::number(secs).rightJustified(2, '0') +
|
||||
|
||||
@@ -26,7 +26,7 @@ extern "C" {
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
#define GCF_DEBUG
|
||||
//#define GCF_DEBUG
|
||||
#endif
|
||||
|
||||
bool texture_failed = false;
|
||||
@@ -194,7 +194,7 @@ void get_clip_frame(Clip* c, long playhead) {
|
||||
#ifdef GCF_DEBUG
|
||||
dout << "GCF ==> RESET" << target_pts << "(" << target_frame->pts << "-" << target_frame->pts+target_frame->pkt_duration << ")";
|
||||
#endif
|
||||
// target_frame = NULL;
|
||||
// target_frame = NULL;
|
||||
reset = true;
|
||||
c->last_invalid_ts = target_pts;
|
||||
} else {
|
||||
|
||||
+12
-12
@@ -66,8 +66,8 @@ Clip* Clip::copy(Sequence* s) {
|
||||
}
|
||||
|
||||
// TODO make a replacemennt for this somehow
|
||||
//if (opening_transition != -1) copy->opening_transition = this->sequence->transitions.at(opening_transition)->copy(copy);
|
||||
//if (closing_transition != -1) copy->closing_transition = this->sequence->transitions.at(closing_transition)->copy(copy);
|
||||
if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip == NULL) copy->opening_transition = get_opening_transition()->copy(copy, NULL);
|
||||
if (get_closing_transition() != NULL && get_closing_transition()->secondary_clip == NULL) copy->closing_transition = get_closing_transition()->copy(copy, NULL);
|
||||
|
||||
copy->recalculateMaxLength();
|
||||
|
||||
@@ -169,8 +169,8 @@ Clip::~Clip() {
|
||||
}
|
||||
}
|
||||
|
||||
//if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION);
|
||||
//if (closing_transition != -1) this->sequence->hard_delete_transition(this, TA_CLOSING_TRANSITION);
|
||||
if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION);
|
||||
if (closing_transition != -1) this->sequence->hard_delete_transition(this, TA_CLOSING_TRANSITION);
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
delete effects.at(i);
|
||||
@@ -181,7 +181,7 @@ Clip::~Clip() {
|
||||
long Clip::get_clip_in_with_transition() {
|
||||
if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip != NULL) {
|
||||
// we must be the secondary clip, so return (timeline in - length)
|
||||
return clip_in - get_opening_transition()->length;
|
||||
return clip_in - get_opening_transition()->get_true_length();
|
||||
}
|
||||
return clip_in;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ long Clip::get_clip_in_with_transition() {
|
||||
long Clip::get_timeline_in_with_transition() {
|
||||
if (get_opening_transition() != NULL && get_opening_transition()->secondary_clip != NULL) {
|
||||
// we must be the secondary clip, so return (timeline in - length)
|
||||
return timeline_in - get_opening_transition()->length;
|
||||
return timeline_in - get_opening_transition()->get_true_length();
|
||||
}
|
||||
return timeline_in;
|
||||
}
|
||||
@@ -197,7 +197,7 @@ long Clip::get_timeline_in_with_transition() {
|
||||
long Clip::get_timeline_out_with_transition() {
|
||||
if (get_closing_transition() != NULL && get_closing_transition()->secondary_clip != NULL) {
|
||||
// we must be the primary clip, so return (timeline out + length2)
|
||||
return timeline_out + get_closing_transition()->length;
|
||||
return timeline_out + get_closing_transition()->get_true_length();
|
||||
} else {
|
||||
return timeline_out;
|
||||
}
|
||||
@@ -293,11 +293,11 @@ int Clip::getHeight() {
|
||||
|
||||
void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points) {
|
||||
if (change_timeline_points) {
|
||||
ca->append(new MoveClipAction(this,
|
||||
qRound((double) timeline_in * multiplier),
|
||||
qRound((double) timeline_out * multiplier),
|
||||
qRound((double) clip_in * multiplier),
|
||||
track));
|
||||
move_clip(ca, this,
|
||||
qRound((double) timeline_in * multiplier),
|
||||
qRound((double) timeline_out * multiplier),
|
||||
qRound((double) clip_in * multiplier),
|
||||
track);
|
||||
}
|
||||
|
||||
for (int i=0;i<effects.size();i++) {
|
||||
|
||||
@@ -67,6 +67,7 @@ struct Clip
|
||||
int media_type;
|
||||
int media_stream;
|
||||
double speed;
|
||||
double cached_fr;
|
||||
bool reverse;
|
||||
bool maintain_audio_pitch;
|
||||
bool autoscale;
|
||||
|
||||
+100
-61
@@ -39,8 +39,7 @@
|
||||
#include <QtMath>
|
||||
#include <QMenu>
|
||||
|
||||
QVector<EffectMeta> video_effects;
|
||||
QVector<EffectMeta> audio_effects;
|
||||
QVector<EffectMeta> effects;
|
||||
QMutex effects_loaded;
|
||||
|
||||
Effect* create_effect(Clip* c, const EffectMeta* em) {
|
||||
@@ -68,17 +67,12 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const EffectMeta* get_internal_meta(int internal_id) {
|
||||
for (int i=0;i<audio_effects.size();i++) {
|
||||
if (audio_effects.at(i).internal == internal_id) {
|
||||
return &audio_effects.at(i);
|
||||
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<video_effects.size();i++) {
|
||||
if (video_effects.at(i).internal == internal_id) {
|
||||
return &video_effects.at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -87,37 +81,40 @@ void load_internal_effects() {
|
||||
|
||||
// internal effects
|
||||
em.type = EFFECT_TYPE_EFFECT;
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
|
||||
em.name = "Volume";
|
||||
em.internal = EFFECT_INTERNAL_VOLUME;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Pan";
|
||||
em.internal = EFFECT_INTERNAL_PAN;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Tone";
|
||||
em.internal = EFFECT_INTERNAL_TONE;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Noise";
|
||||
em.internal = EFFECT_INTERNAL_NOISE;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
|
||||
em.name = "Transform";
|
||||
em.category = "Distort";
|
||||
em.internal = EFFECT_INTERNAL_TRANSFORM;
|
||||
video_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Corner Pin";
|
||||
em.category = "Distort";
|
||||
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
||||
video_effects.append(em);
|
||||
em.name = "Corner Pin";
|
||||
em.category = "Distort";
|
||||
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Text";
|
||||
em.category = "Render";
|
||||
em.internal = EFFECT_INTERNAL_TEXT;
|
||||
video_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Timecode";
|
||||
em.category = "Render";
|
||||
@@ -127,12 +124,12 @@ void load_internal_effects() {
|
||||
em.name = "Solid";
|
||||
em.category = "Render";
|
||||
em.internal = EFFECT_INTERNAL_SOLID;
|
||||
video_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Shake";
|
||||
em.category = "Distort";
|
||||
em.internal = EFFECT_INTERNAL_SHAKE;
|
||||
video_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
// internal transitions
|
||||
em.type = EFFECT_TYPE_TRANSITION;
|
||||
@@ -140,23 +137,21 @@ void load_internal_effects() {
|
||||
|
||||
em.name = "Cross Dissolve";
|
||||
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
|
||||
video_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Cube";
|
||||
em.internal = TRANSITION_INTERNAL_CUBE;
|
||||
video_effects.append(em);
|
||||
em.subtype = EFFECT_TYPE_AUDIO;
|
||||
|
||||
em.name = "Linear Fade";
|
||||
em.internal = TRANSITION_INTERNAL_LINEARFADE;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Exponential Fade";
|
||||
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
|
||||
em.name = "Logarithmic Fade";
|
||||
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
|
||||
audio_effects.append(em);
|
||||
effects.append(em);
|
||||
}
|
||||
|
||||
void load_shader_effects() {
|
||||
@@ -187,11 +182,12 @@ void load_shader_effects() {
|
||||
if (!effect_name.isEmpty()) {
|
||||
EffectMeta em;
|
||||
em.type = EFFECT_TYPE_EFFECT;
|
||||
em.subtype = EFFECT_TYPE_VIDEO;
|
||||
em.name = effect_name;
|
||||
em.category = effect_cat;
|
||||
em.filename = entries.at(i);
|
||||
em.internal = -1;
|
||||
video_effects.append(em);
|
||||
effects.append(em);
|
||||
} else {
|
||||
dout << "[ERROR] Invalid effect found in" << entries.at(i);
|
||||
}
|
||||
@@ -231,10 +227,9 @@ void EffectInit::run() {
|
||||
Effect::Effect(Clip* c, const EffectMeta *em) :
|
||||
parent_clip(c),
|
||||
meta(em),
|
||||
length(30),
|
||||
enable_shader(false),
|
||||
enable_coords(false),
|
||||
enable_superimpose(false),
|
||||
enable_superimpose(false),
|
||||
glslProgram(NULL),
|
||||
texture(NULL),
|
||||
isOpen(false),
|
||||
@@ -305,8 +300,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);
|
||||
field->id = id;
|
||||
EffectField* field = row->add_field(type, id);
|
||||
connect(field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
@@ -457,9 +451,9 @@ void Effect::copy_field_keyframes(Effect* e) {
|
||||
}
|
||||
}
|
||||
|
||||
EffectRow* Effect::add_row(const QString& name) {
|
||||
EffectRow* row = new EffectRow(this, ui_layout, name, rows.size());
|
||||
rows.append(row);
|
||||
EffectRow* Effect::add_row(const QString& name, bool savable) {
|
||||
EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size());
|
||||
rows.append(row);
|
||||
return row;
|
||||
}
|
||||
|
||||
@@ -468,7 +462,21 @@ 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 *Effect::gizmo(int i) {
|
||||
return gizmos.at(i);
|
||||
}
|
||||
|
||||
int Effect::gizmo_count(){
|
||||
return gizmos.size();
|
||||
}
|
||||
|
||||
void Effect::refresh() {}
|
||||
@@ -679,31 +687,32 @@ void Effect::load(QXmlStreamReader& stream) {
|
||||
void Effect::save(QXmlStreamWriter& stream) {
|
||||
stream.writeAttribute("name", meta->name);
|
||||
stream.writeAttribute("enabled", QString::number(is_enabled()));
|
||||
stream.writeAttribute("length", QString::number(length));
|
||||
|
||||
for (int i=0;i<rows.size();i++) {
|
||||
EffectRow* row = rows.at(i);
|
||||
stream.writeStartElement("row"); // row
|
||||
stream.writeStartElement("keyframes"); // keyframes
|
||||
stream.writeAttribute("enabled", QString::number(row->isKeyframing()));
|
||||
for (int j=0;j<row->keyframe_times.size();j++) {
|
||||
stream.writeStartElement("key"); // key
|
||||
stream.writeAttribute("frame", QString::number(row->keyframe_times.at(j)));
|
||||
stream.writeAttribute("type", QString::number(row->keyframe_types.at(j)));
|
||||
stream.writeEndElement(); // key
|
||||
if (row->savable) {
|
||||
stream.writeStartElement("row"); // row
|
||||
stream.writeStartElement("keyframes"); // keyframes
|
||||
stream.writeAttribute("enabled", QString::number(row->isKeyframing()));
|
||||
for (int j=0;j<row->keyframe_times.size();j++) {
|
||||
stream.writeStartElement("key"); // key
|
||||
stream.writeAttribute("frame", QString::number(row->keyframe_times.at(j)));
|
||||
stream.writeAttribute("type", QString::number(row->keyframe_types.at(j)));
|
||||
stream.writeEndElement(); // key
|
||||
}
|
||||
stream.writeEndElement(); // keyframes
|
||||
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->keyframe_data.size();k++) {
|
||||
stream.writeTextElement("key", save_data_to_string(field->type, field->keyframe_data.at(k)));
|
||||
}
|
||||
stream.writeEndElement(); // field
|
||||
}
|
||||
stream.writeEndElement(); // row
|
||||
}
|
||||
stream.writeEndElement(); // keyframes
|
||||
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->keyframe_data.size();k++) {
|
||||
stream.writeTextElement("key", save_data_to_string(field->type, field->keyframe_data.at(k)));
|
||||
}
|
||||
stream.writeEndElement(); // field
|
||||
}
|
||||
stream.writeEndElement(); // row
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,6 +853,36 @@ void Effect::process_audio(double, double, quint8*, int, int) {
|
||||
}*/
|
||||
}
|
||||
|
||||
void Effect::gizmo_draw(double, GLTextureCoords &) {}
|
||||
void Effect::gizmo_move(EffectGizmo* , int , int , double ) {}
|
||||
|
||||
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);
|
||||
|
||||
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 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);
|
||||
|
||||
g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Effect::are_gizmos_enabled() {
|
||||
return (gizmos.size() > 0);
|
||||
}
|
||||
|
||||
void Effect::redraw(double) {
|
||||
/*
|
||||
// run javascript
|
||||
|
||||
+34
-16
@@ -1,4 +1,4 @@
|
||||
#ifndef EFFECT_H
|
||||
#ifndef EFFECT_H
|
||||
#define EFFECT_H
|
||||
|
||||
#include <QObject>
|
||||
@@ -15,6 +15,7 @@ class QWidget;
|
||||
class CollapsibleWidget;
|
||||
class QGridLayout;
|
||||
class QPushButton;
|
||||
class QMouseEvent;
|
||||
|
||||
struct Clip;
|
||||
class QXmlStreamReader;
|
||||
@@ -30,15 +31,15 @@ struct EffectMeta {
|
||||
QString filename;
|
||||
int internal;
|
||||
int type;
|
||||
int subtype;
|
||||
};
|
||||
|
||||
extern QVector<EffectMeta> video_effects;
|
||||
extern QVector<EffectMeta> audio_effects;
|
||||
extern QVector<EffectMeta> effects;
|
||||
|
||||
double log_volume(double linear);
|
||||
void init_effects();
|
||||
Effect* create_effect(Clip* c, const EffectMeta *em);
|
||||
const EffectMeta* get_internal_meta(int internal_id);
|
||||
const EffectMeta* get_internal_meta(int internal_id, int type);
|
||||
|
||||
extern QMutex effects_loaded;
|
||||
|
||||
@@ -64,7 +65,6 @@ extern QMutex effects_loaded;
|
||||
|
||||
|
||||
|
||||
|
||||
#define EFFECT_INTERNAL_CORNERPIN 12
|
||||
#define EFFECT_INTERNAL_COUNT 13
|
||||
|
||||
@@ -77,27 +77,36 @@ struct GLTextureCoords {
|
||||
|
||||
int vertexTopLeftX;
|
||||
int vertexTopLeftY;
|
||||
int vertexTopLeftZ;
|
||||
int vertexTopRightX;
|
||||
int vertexTopRightY;
|
||||
int vertexTopRightZ;
|
||||
int vertexBottomLeftX;
|
||||
int vertexBottomLeftY;
|
||||
int vertexBottomLeftZ;
|
||||
int vertexBottomRightX;
|
||||
int vertexBottomRightY;
|
||||
int vertexBottomRightZ;
|
||||
|
||||
double textureTopLeftX;
|
||||
double textureTopLeftY;
|
||||
double textureTopRightX;
|
||||
double textureTopRightY;
|
||||
double textureBottomRightX;
|
||||
double textureBottomRightY;
|
||||
double textureBottomLeftX;
|
||||
double textureBottomLeftY;
|
||||
float textureTopLeftX;
|
||||
float textureTopLeftY;
|
||||
float textureTopLeftQ;
|
||||
float textureTopRightX;
|
||||
float textureTopRightY;
|
||||
float textureTopRightQ;
|
||||
float textureBottomRightX;
|
||||
float textureBottomRightY;
|
||||
float textureBottomRightQ;
|
||||
float textureBottomLeftX;
|
||||
float textureBottomLeftY;
|
||||
float textureBottomLeftQ;
|
||||
};
|
||||
|
||||
qint16 mix_audio_sample(qint16 a, qint16 b);
|
||||
|
||||
#include "effectfield.h"
|
||||
#include "effectrow.h"
|
||||
#include "effectgizmo.h"
|
||||
|
||||
class Effect : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -106,15 +115,18 @@ public:
|
||||
~Effect();
|
||||
Clip* parent_clip;
|
||||
const EffectMeta* meta;
|
||||
long length; // used only for transitions
|
||||
int id;
|
||||
QString name;
|
||||
CollapsibleWidget* container;
|
||||
|
||||
EffectRow* add_row(const QString &name);
|
||||
EffectRow* add_row(const QString &name, bool savable = true);
|
||||
EffectRow* row(int i);
|
||||
int row_count();
|
||||
|
||||
EffectGizmo* add_gizmo(int type);
|
||||
EffectGizmo* gizmo(int i);
|
||||
int gizmo_count();
|
||||
|
||||
bool is_enabled();
|
||||
void set_enabled(bool b);
|
||||
|
||||
@@ -134,7 +146,7 @@ public:
|
||||
|
||||
bool enable_shader;
|
||||
bool enable_coords;
|
||||
bool enable_superimpose;
|
||||
bool enable_superimpose;
|
||||
|
||||
int getIterations();
|
||||
void setIterations(int i);
|
||||
@@ -145,6 +157,11 @@ public:
|
||||
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
|
||||
virtual GLuint process_superimpose(double timecode);
|
||||
virtual void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
|
||||
|
||||
virtual void gizmo_draw(double timecode, GLTextureCoords& coords);
|
||||
virtual void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode);
|
||||
void gizmo_world_to_screen();
|
||||
bool are_gizmos_enabled();
|
||||
public slots:
|
||||
void field_changed();
|
||||
private slots:
|
||||
@@ -170,6 +187,7 @@ private:
|
||||
|
||||
bool isOpen;
|
||||
QVector<EffectRow*> rows;
|
||||
QVector<EffectGizmo*> gizmos;
|
||||
QGridLayout* ui_layout;
|
||||
QWidget* ui;
|
||||
bool bound;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "io/math.h"
|
||||
#include <QtMath>
|
||||
|
||||
EffectField::EffectField(EffectRow *parent, int t) : parent_row(parent), type(t) {
|
||||
EffectField::EffectField(EffectRow *parent, int t, const QString &i) : parent_row(parent), type(t), id(i) {
|
||||
switch (t) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ class EffectRow;
|
||||
class EffectField : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EffectField(EffectRow* parent, int t);
|
||||
EffectField(EffectRow* parent, int t, const QString& i);
|
||||
EffectRow* parent_row;
|
||||
int type;
|
||||
QString id;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "effectgizmo.h"
|
||||
|
||||
EffectGizmo::EffectGizmo(int type) :
|
||||
type(type),
|
||||
cursor(-1)
|
||||
{
|
||||
int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1;
|
||||
world_pos.resize(point_count);
|
||||
screen_pos.resize(point_count);
|
||||
|
||||
color = Qt::white;
|
||||
}
|
||||
|
||||
int EffectGizmo::get_point_count() {
|
||||
return world_pos.size();
|
||||
}
|
||||
|
||||
int EffectGizmo::get_type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
int EffectGizmo::get_cursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
void EffectGizmo::set_cursor(int c) {
|
||||
cursor = c;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef EFFECTGIZMO_H
|
||||
#define EFFECTGIZMO_H
|
||||
|
||||
#define GIZMO_TYPE_DOT 0
|
||||
#define GIZMO_TYPE_POLY 1
|
||||
|
||||
#define GIZMO_DOT_SIZE 2.5F
|
||||
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
#include <QPoint>
|
||||
#include <QVector>
|
||||
#include <QColor>
|
||||
|
||||
class EffectGizmo
|
||||
{
|
||||
public:
|
||||
EffectGizmo(int type);
|
||||
|
||||
QVector<QPoint> world_pos;
|
||||
QVector<QPoint> screen_pos;
|
||||
QColor color;
|
||||
int get_point_count();
|
||||
|
||||
int get_type();
|
||||
|
||||
int get_cursor();
|
||||
void set_cursor(int c);
|
||||
private:
|
||||
int type;
|
||||
int cursor;
|
||||
};
|
||||
|
||||
#endif // EFFECTGIZMO_H
|
||||
+42
-36
@@ -14,8 +14,9 @@
|
||||
#include "effect.h"
|
||||
#include "ui/viewerwidget.h"
|
||||
|
||||
EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, int row) :
|
||||
EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row) :
|
||||
parent_effect(parent),
|
||||
savable(save),
|
||||
keyframing(false),
|
||||
ui(uilayout),
|
||||
name(n),
|
||||
@@ -25,43 +26,45 @@ EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, in
|
||||
label = new QLabel(name);
|
||||
ui->addWidget(label, row, 0);
|
||||
|
||||
QSize button_size(20, 20);
|
||||
QSize icon_size(12, 12);
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
QSize button_size(20, 20);
|
||||
QSize icon_size(12, 12);
|
||||
|
||||
QHBoxLayout* key_controls = new QHBoxLayout();
|
||||
key_controls->setSpacing(0);
|
||||
key_controls->setMargin(0);
|
||||
key_controls->addStretch();
|
||||
QHBoxLayout* key_controls = new QHBoxLayout();
|
||||
key_controls->setSpacing(0);
|
||||
key_controls->setMargin(0);
|
||||
key_controls->addStretch();
|
||||
|
||||
left_key_nav = new QPushButton("<");
|
||||
left_key_nav->setVisible(false);
|
||||
left_key_nav->setMaximumSize(button_size);
|
||||
key_controls->addWidget(left_key_nav);
|
||||
connect(left_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_previous_key()));
|
||||
left_key_nav = new QPushButton("<");
|
||||
left_key_nav->setVisible(false);
|
||||
left_key_nav->setMaximumSize(button_size);
|
||||
key_controls->addWidget(left_key_nav);
|
||||
connect(left_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_previous_key()));
|
||||
|
||||
key_addremove = new QPushButton(".");
|
||||
key_addremove->setVisible(false);
|
||||
key_addremove->setMaximumSize(button_size);
|
||||
key_controls->addWidget(key_addremove);
|
||||
connect(key_addremove, SIGNAL(clicked(bool)), this, SLOT(toggle_key()));
|
||||
key_addremove = new QPushButton(".");
|
||||
key_addremove->setVisible(false);
|
||||
key_addremove->setMaximumSize(button_size);
|
||||
key_controls->addWidget(key_addremove);
|
||||
connect(key_addremove, SIGNAL(clicked(bool)), this, SLOT(toggle_key()));
|
||||
|
||||
right_key_nav = new QPushButton(">");
|
||||
right_key_nav->setVisible(false);
|
||||
right_key_nav->setMaximumSize(button_size);
|
||||
key_controls->addWidget(right_key_nav);
|
||||
connect(right_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_next_key()));
|
||||
right_key_nav = new QPushButton(">");
|
||||
right_key_nav->setVisible(false);
|
||||
right_key_nav->setMaximumSize(button_size);
|
||||
key_controls->addWidget(right_key_nav);
|
||||
connect(right_key_nav, SIGNAL(clicked(bool)), this, SLOT(goto_next_key()));
|
||||
|
||||
keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), "");
|
||||
keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
|
||||
keyframe_enable->setMaximumSize(button_size);
|
||||
keyframe_enable->setIconSize(icon_size);
|
||||
keyframe_enable->setCheckable(true);
|
||||
keyframe_enable->setToolTip("Enable Keyframes");
|
||||
connect(keyframe_enable, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_enabled(bool)));
|
||||
connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool)));
|
||||
key_controls->addWidget(keyframe_enable);
|
||||
keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), "");
|
||||
keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
|
||||
keyframe_enable->setMaximumSize(button_size);
|
||||
keyframe_enable->setIconSize(icon_size);
|
||||
keyframe_enable->setCheckable(true);
|
||||
keyframe_enable->setToolTip("Enable Keyframes");
|
||||
connect(keyframe_enable, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_enabled(bool)));
|
||||
connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool)));
|
||||
key_controls->addWidget(keyframe_enable);
|
||||
|
||||
ui->addLayout(key_controls, row, 6);
|
||||
ui->addLayout(key_controls, row, 6);
|
||||
}
|
||||
}
|
||||
|
||||
bool EffectRow::isKeyframing() {
|
||||
@@ -69,8 +72,10 @@ bool EffectRow::isKeyframing() {
|
||||
}
|
||||
|
||||
void EffectRow::setKeyframing(bool b) {
|
||||
keyframing = b;
|
||||
keyframe_enable->setChecked(b);
|
||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||
keyframing = b;
|
||||
keyframe_enable->setChecked(b);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectRow::set_keyframe_enabled(bool enabled) {
|
||||
@@ -144,11 +149,12 @@ void EffectRow::goto_next_key() {
|
||||
if (key != LONG_MAX) panel_sequence_viewer->seek(key);
|
||||
}
|
||||
|
||||
EffectField* EffectRow::add_field(int type, int colspan) {
|
||||
EffectField* field = new EffectField(this, type);
|
||||
EffectField* EffectRow::add_field(int type, const QString& id, int colspan) {
|
||||
EffectField* field = new EffectField(this, type, id);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -14,9 +14,9 @@ class QPushButton;
|
||||
class EffectRow : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EffectRow(Effect* parent, QGridLayout* uilayout, const QString& n, int row);
|
||||
EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row);
|
||||
~EffectRow();
|
||||
EffectField* add_field(int type, int colspan = 1);
|
||||
EffectField* add_field(int type, const QString &id, int colspan = 1);
|
||||
EffectField* field(int i);
|
||||
int fieldCount();
|
||||
void set_keyframe_now(bool undoable);
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
void delete_keyframe_at_time(KeyframeDelete* kd, long time);
|
||||
QLabel* label;
|
||||
Effect* parent_effect;
|
||||
bool savable;
|
||||
|
||||
bool isKeyframing();
|
||||
void setKeyframing(bool);
|
||||
|
||||
@@ -57,6 +57,7 @@ long Sequence::getEndFrame() {
|
||||
void Sequence::hard_delete_transition(Clip *c, int type) {
|
||||
int transition_index = (type == TA_OPENING_TRANSITION) ? c->opening_transition : c->closing_transition;
|
||||
if (transition_index > -1) {
|
||||
bool del = true;
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
Clip* cc = clips.at(i);
|
||||
if (cc != NULL
|
||||
@@ -64,12 +65,16 @@ void Sequence::hard_delete_transition(Clip *c, int type) {
|
||||
&& (cc->opening_transition == transition_index
|
||||
|| cc->closing_transition == transition_index)) {
|
||||
// another clip is using this, don't delete just yet
|
||||
return;
|
||||
del = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete transitions.at(transition_index);
|
||||
transitions[transition_index] = NULL;
|
||||
if (del) {
|
||||
delete transitions.at(transition_index);
|
||||
transitions[transition_index] = NULL;
|
||||
}
|
||||
|
||||
if (type == TA_OPENING_TRANSITION) {
|
||||
c->opening_transition = -1;
|
||||
} else {
|
||||
|
||||
+31
-2
@@ -11,10 +11,25 @@
|
||||
#include "effects/internal/logarithmicfadetransition.h"
|
||||
#include "effects/internal/cubetransition.h"
|
||||
|
||||
#include "ui/labelslider.h"
|
||||
|
||||
#include "panels/panels.h"
|
||||
#include "panels/timeline.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
Transition::Transition(Clip* c, Clip* s, const EffectMeta* em) : Effect(c, em), secondary_clip(s) {
|
||||
add_row("Length:")->add_field(EFFECT_FIELD_DOUBLE);
|
||||
Transition::Transition(Clip* c, Clip* s, const EffectMeta* em) :
|
||||
Effect(c, em), secondary_clip(s),
|
||||
length(30)
|
||||
{
|
||||
length_field = add_row("Length:", false)->add_field(EFFECT_FIELD_DOUBLE, "length");
|
||||
connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider()));
|
||||
length_field->set_double_default_value(30);
|
||||
length_field->set_double_minimum_value(0);
|
||||
|
||||
LabelSlider* length_ui_ele = static_cast<LabelSlider*>(length_field->ui_element);
|
||||
length_ui_ele->set_display_type(LABELSLIDER_FRAMENUMBER);
|
||||
length_ui_ele->set_frame_rate(parent_clip->sequence->frame_rate);
|
||||
}
|
||||
|
||||
int Transition::copy(Clip *c, Clip* s) {
|
||||
@@ -23,6 +38,15 @@ int Transition::copy(Clip *c, Clip* s) {
|
||||
return copy_index;
|
||||
}
|
||||
|
||||
void Transition::set_length(long l) {
|
||||
length = l;
|
||||
length_field->set_double_value(l);
|
||||
}
|
||||
|
||||
long Transition::get_true_length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
long Transition::get_length() {
|
||||
if (secondary_clip != NULL) {
|
||||
return length * 2;
|
||||
@@ -30,6 +54,11 @@ long Transition::get_length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
void Transition::set_length_from_slider() {
|
||||
set_length(length_field->get_double_value(0));
|
||||
update_ui(false);
|
||||
}
|
||||
|
||||
Transition* get_transition_from_meta(Clip* c, Clip* s, const EffectMeta* em) {
|
||||
if (!em->filename.isEmpty()) {
|
||||
// load effect from file
|
||||
|
||||
@@ -17,11 +17,19 @@
|
||||
int create_transition(Clip* c, Clip* s, const EffectMeta* em);
|
||||
|
||||
class Transition : public Effect {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Transition(Clip* c, Clip* s, const EffectMeta* em);
|
||||
int copy(Clip* c, Clip* s);
|
||||
Clip* secondary_clip;
|
||||
void set_length(long l);
|
||||
long get_true_length();
|
||||
long get_length();
|
||||
private slots:
|
||||
void set_length_from_slider();
|
||||
private:
|
||||
long length; // used only for transitions
|
||||
EffectField* length_field;
|
||||
};
|
||||
|
||||
#endif // TRANSITION_H
|
||||
|
||||
+59
-13
@@ -21,6 +21,7 @@
|
||||
#include "ui/viewerwidget.h"
|
||||
#include "project/marker.h"
|
||||
#include "mainwindow.h"
|
||||
#include "io/clipboard.h"
|
||||
#include "debug.h"
|
||||
|
||||
QUndoStack undo_stack;
|
||||
@@ -224,9 +225,10 @@ void AddEffectCommand::redo() {
|
||||
mainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
AddTransitionCommand::AddTransitionCommand(Clip* c, Clip *s, const EffectMeta *itransition, int itype, int ilength) :
|
||||
AddTransitionCommand::AddTransitionCommand(Clip* c, Clip *s, Transition* copy, const EffectMeta *itransition, int itype, int ilength) :
|
||||
clip(c),
|
||||
secondary(s),
|
||||
transition_to_copy(copy),
|
||||
transition(itransition),
|
||||
type(itype),
|
||||
length(ilength),
|
||||
@@ -236,21 +238,38 @@ AddTransitionCommand::AddTransitionCommand(Clip* c, Clip *s, const EffectMeta *i
|
||||
void AddTransitionCommand::undo() {
|
||||
clip->sequence->hard_delete_transition(clip, type);
|
||||
if (secondary != NULL) secondary->sequence->hard_delete_transition(secondary, (type == TA_OPENING_TRANSITION) ? TA_CLOSING_TRANSITION : TA_OPENING_TRANSITION);
|
||||
|
||||
if (type == TA_OPENING_TRANSITION) {
|
||||
clip->opening_transition = old_ptransition;
|
||||
if (secondary != NULL) secondary->closing_transition = old_stransition;
|
||||
} else {
|
||||
clip->closing_transition = old_ptransition;
|
||||
if (secondary != NULL) secondary->opening_transition = old_stransition;
|
||||
}
|
||||
|
||||
mainWindow->setWindowModified(old_project_changed);
|
||||
}
|
||||
|
||||
void AddTransitionCommand::redo() {
|
||||
if (type == TA_OPENING_TRANSITION) {
|
||||
clip->opening_transition = create_transition(clip, secondary, transition);
|
||||
if (secondary != NULL) secondary->closing_transition = clip->opening_transition;
|
||||
old_ptransition = clip->opening_transition;
|
||||
clip->opening_transition = (transition_to_copy == NULL) ? create_transition(clip, secondary, transition) : transition_to_copy->copy(clip, NULL);
|
||||
if (secondary != NULL) {
|
||||
old_stransition = secondary->closing_transition;
|
||||
secondary->closing_transition = clip->opening_transition;
|
||||
}
|
||||
if (length > 0) {
|
||||
clip->get_opening_transition()->length = length;
|
||||
clip->get_opening_transition()->set_length(length);
|
||||
}
|
||||
} else {
|
||||
clip->closing_transition = create_transition(clip, secondary, transition);
|
||||
if (secondary != NULL) secondary->opening_transition = clip->closing_transition;
|
||||
old_ptransition = clip->closing_transition;
|
||||
clip->closing_transition = (transition_to_copy == NULL) ? create_transition(clip, secondary, transition) : transition_to_copy->copy(clip, NULL);
|
||||
if (secondary != NULL) {
|
||||
old_stransition = secondary->opening_transition;
|
||||
secondary->opening_transition = clip->closing_transition;
|
||||
}
|
||||
if (length > 0) {
|
||||
clip->get_closing_transition()->length = length;
|
||||
clip->get_closing_transition()->set_length(length);
|
||||
}
|
||||
}
|
||||
mainWindow->setWindowModified(true);
|
||||
@@ -265,14 +284,14 @@ ModifyTransitionCommand::ModifyTransitionCommand(Clip* c, int itype, long ilengt
|
||||
|
||||
void ModifyTransitionCommand::undo() {
|
||||
Transition* t = (type == TA_OPENING_TRANSITION) ? clip->get_opening_transition() : clip->get_closing_transition();
|
||||
t->length = old_length;
|
||||
t->set_length(old_length);
|
||||
mainWindow->setWindowModified(old_project_changed);
|
||||
}
|
||||
|
||||
void ModifyTransitionCommand::redo() {
|
||||
Transition* t = (type == TA_OPENING_TRANSITION) ? clip->get_opening_transition() : clip->get_closing_transition();
|
||||
old_length = t->length;
|
||||
t->length = new_length;
|
||||
old_length = t->get_true_length();
|
||||
t->set_length(new_length);
|
||||
mainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
@@ -484,6 +503,7 @@ void AddClipCommand::undo() {
|
||||
Clip* c = seq->clips.last();
|
||||
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
|
||||
undone_clips.prepend(c);
|
||||
if (c->open) close_clip(c);
|
||||
seq->clips.removeLast();
|
||||
}
|
||||
mainWindow->setWindowModified(old_project_changed);
|
||||
@@ -504,6 +524,8 @@ void AddClipCommand::redo() {
|
||||
for (int j=0;j<original->linked.size();j++) {
|
||||
copy->linked[j] = original->linked.at(j) + linkOffset;
|
||||
}
|
||||
if (original->opening_transition > -1) copy->opening_transition = original->get_opening_transition()->copy(copy, NULL);
|
||||
if (original->closing_transition > -1) copy->closing_transition = original->get_closing_transition()->copy(copy, NULL);
|
||||
seq->clips.append(copy);
|
||||
}
|
||||
}
|
||||
@@ -1233,13 +1255,13 @@ RemoveClipsFromClipboard::~RemoveClipsFromClipboard() {
|
||||
}
|
||||
|
||||
void RemoveClipsFromClipboard::undo() {
|
||||
panel_timeline->clip_clipboard.insert(pos, clip);
|
||||
clipboard.insert(pos, clip);
|
||||
done = false;
|
||||
}
|
||||
|
||||
void RemoveClipsFromClipboard::redo() {
|
||||
clip = panel_timeline->clip_clipboard.at(pos);
|
||||
panel_timeline->clip_clipboard.removeAt(pos);
|
||||
clip = static_cast<Clip*>(clipboard.at(pos));
|
||||
clipboard.removeAt(pos);
|
||||
done = true;
|
||||
}
|
||||
|
||||
@@ -1277,3 +1299,27 @@ void SetPointer::redo() {
|
||||
*p = new_data;
|
||||
mainWindow->setWindowModified(true);
|
||||
}
|
||||
|
||||
MoveGizmo::MoveGizmo(Effect *e, EffectGizmo *g, int x_movement, int y_movement, double tc) :
|
||||
effect(e),
|
||||
gizmo(g),
|
||||
x(x_movement),
|
||||
y(y_movement),
|
||||
timecode(tc),
|
||||
done(true),
|
||||
old_changed(mainWindow->isWindowModified())
|
||||
{}
|
||||
|
||||
void MoveGizmo::undo() {
|
||||
effect->gizmo_move(gizmo, -x, -y, timecode);
|
||||
mainWindow->setWindowModified(old_changed);
|
||||
done = false;
|
||||
}
|
||||
|
||||
void MoveGizmo::redo() {
|
||||
if (!done) {
|
||||
effect->gizmo_move(gizmo, x, y, timecode);
|
||||
mainWindow->setWindowModified(true);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -9,6 +9,7 @@ class SourceTable;
|
||||
class EffectRow;
|
||||
class EffectField;
|
||||
class Transition;
|
||||
class EffectGizmo;
|
||||
struct Clip;
|
||||
struct Sequence;
|
||||
struct Media;
|
||||
@@ -101,16 +102,19 @@ private:
|
||||
|
||||
class AddTransitionCommand : public QUndoCommand {
|
||||
public:
|
||||
AddTransitionCommand(Clip* c, Clip* s, const EffectMeta* itransition, int itype, int ilength);
|
||||
AddTransitionCommand(Clip* c, Clip* s, Transition *copy, const EffectMeta* itransition, int itype, int ilength);
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
Clip* clip;
|
||||
Clip* secondary;
|
||||
Transition* transition_to_copy;
|
||||
const EffectMeta* transition;
|
||||
int type;
|
||||
int length;
|
||||
bool old_project_changed;
|
||||
int old_ptransition;
|
||||
int old_stransition;
|
||||
};
|
||||
|
||||
class ModifyTransitionCommand : public QUndoCommand {
|
||||
@@ -594,4 +598,19 @@ private:
|
||||
void* old_data;
|
||||
};
|
||||
|
||||
class MoveGizmo : public QUndoCommand {
|
||||
public:
|
||||
MoveGizmo(Effect* e, EffectGizmo* g, int x_movement, int y_movement, double tc);
|
||||
void undo();
|
||||
void redo();
|
||||
private:
|
||||
Effect* effect;
|
||||
EffectGizmo* gizmo;
|
||||
int x;
|
||||
int y;
|
||||
double timecode;
|
||||
bool done;
|
||||
bool old_changed;
|
||||
};
|
||||
|
||||
#endif // UNDO_H
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2018-05-11T10:31:59
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui multimedia opengl
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = Olive
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
panels/project.cpp \
|
||||
panels/effectcontrols.cpp \
|
||||
panels/viewer.cpp \
|
||||
panels/timeline.cpp \
|
||||
ui/sourcetable.cpp \
|
||||
dialogs/aboutdialog.cpp \
|
||||
ui/timelinewidget.cpp \
|
||||
io/media.cpp \
|
||||
project/sequence.cpp \
|
||||
project/clip.cpp \
|
||||
playback/playback.cpp \
|
||||
playback/audio.cpp \
|
||||
io/config.cpp \
|
||||
dialogs/newsequencedialog.cpp \
|
||||
ui/viewerwidget.cpp \
|
||||
ui/viewercontainer.cpp \
|
||||
dialogs/exportdialog.cpp \
|
||||
ui/collapsiblewidget.cpp \
|
||||
panels/panels.cpp \
|
||||
playback/cacher.cpp \
|
||||
io/exportthread.cpp \
|
||||
ui/timelineheader.cpp \
|
||||
io/previewgenerator.cpp \
|
||||
ui/labelslider.cpp \
|
||||
dialogs/preferencesdialog.cpp \
|
||||
ui/audiomonitor.cpp \
|
||||
project/undo.cpp \
|
||||
ui/scrollarea.cpp \
|
||||
ui/comboboxex.cpp \
|
||||
ui/colorbutton.cpp \
|
||||
dialogs/replaceclipmediadialog.cpp \
|
||||
ui/fontcombobox.cpp \
|
||||
ui/checkboxex.cpp \
|
||||
ui/keyframeview.cpp \
|
||||
ui/texteditex.cpp \
|
||||
dialogs/demonotice.cpp \
|
||||
project/marker.cpp \
|
||||
dialogs/speeddialog.cpp \
|
||||
dialogs/mediapropertiesdialog.cpp \
|
||||
io/crc32.cpp \
|
||||
dialogs/loaddialog.cpp \
|
||||
debug.cpp \
|
||||
io/path.cpp \
|
||||
effects/internal/linearfadetransition.cpp \
|
||||
effects/internal/transformeffect.cpp \
|
||||
effects/internal/solideffect.cpp \
|
||||
effects/internal/texteffect.cpp \
|
||||
effects/internal/audionoiseeffect.cpp \
|
||||
effects/internal/paneffect.cpp \
|
||||
effects/internal/toneeffect.cpp \
|
||||
effects/internal/volumeeffect.cpp \
|
||||
effects/internal/crossdissolvetransition.cpp \
|
||||
effects/internal/shakeeffect.cpp \
|
||||
effects/internal/exponentialfadetransition.cpp \
|
||||
effects/internal/logarithmicfadetransition.cpp \
|
||||
effects/internal/cornerpineffect.cpp \
|
||||
io/math.cpp \
|
||||
io/qpainterwrapper.cpp \
|
||||
project/effect.cpp \
|
||||
project/transition.cpp \
|
||||
project/effectrow.cpp \
|
||||
project/effectfield.cpp \
|
||||
effects/internal/cubetransition.cpp \
|
||||
project/effectgizmo.cpp \
|
||||
io/clipboard.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
panels/project.h \
|
||||
panels/effectcontrols.h \
|
||||
panels/viewer.h \
|
||||
panels/timeline.h \
|
||||
ui/sourcetable.h \
|
||||
dialogs/aboutdialog.h \
|
||||
ui/timelinewidget.h \
|
||||
io/media.h \
|
||||
project/sequence.h \
|
||||
project/clip.h \
|
||||
playback/playback.h \
|
||||
playback/audio.h \
|
||||
io/config.h \
|
||||
dialogs/newsequencedialog.h \
|
||||
ui/viewerwidget.h \
|
||||
ui/viewercontainer.h \
|
||||
dialogs/exportdialog.h \
|
||||
ui/collapsiblewidget.h \
|
||||
panels/panels.h \
|
||||
playback/cacher.h \
|
||||
io/exportthread.h \
|
||||
ui/timelinetools.h \
|
||||
ui/timelineheader.h \
|
||||
io/previewgenerator.h \
|
||||
ui/labelslider.h \
|
||||
dialogs/preferencesdialog.h \
|
||||
ui/audiomonitor.h \
|
||||
project/undo.h \
|
||||
ui/scrollarea.h \
|
||||
ui/comboboxex.h \
|
||||
ui/colorbutton.h \
|
||||
dialogs/replaceclipmediadialog.h \
|
||||
ui/fontcombobox.h \
|
||||
ui/checkboxex.h \
|
||||
ui/keyframeview.h \
|
||||
ui/texteditex.h \
|
||||
dialogs/demonotice.h \
|
||||
project/marker.h \
|
||||
project/selection.h \
|
||||
dialogs/speeddialog.h \
|
||||
dialogs/mediapropertiesdialog.h \
|
||||
io/crc32.h \
|
||||
dialogs/loaddialog.h \
|
||||
debug.h \
|
||||
io/path.h \
|
||||
effects/internal/transformeffect.h \
|
||||
effects/internal/solideffect.h \
|
||||
effects/internal/texteffect.h \
|
||||
effects/internal/audionoiseeffect.h \
|
||||
effects/internal/paneffect.h \
|
||||
effects/internal/toneeffect.h \
|
||||
effects/internal/volumeeffect.h \
|
||||
effects/internal/shakeeffect.h \
|
||||
effects/internal/linearfadetransition.h \
|
||||
effects/internal/crossdissolvetransition.h \
|
||||
effects/internal/exponentialfadetransition.h \
|
||||
effects/internal/logarithmicfadetransition.h \
|
||||
effects/internal/cornerpineffect.h \
|
||||
io/math.h \
|
||||
io/qpainterwrapper.h \
|
||||
project/effect.h \
|
||||
project/transition.h \
|
||||
project/effectrow.h \
|
||||
project/effectfield.h \
|
||||
effects/internal/cubetransition.h \
|
||||
project/effectgizmo.h \
|
||||
io/clipboard.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui \
|
||||
panels/project.ui \
|
||||
panels/effectcontrols.ui \
|
||||
panels/viewer.ui \
|
||||
panels/timeline.ui \
|
||||
dialogs/aboutdialog.ui \
|
||||
dialogs/newsequencedialog.ui \
|
||||
dialogs/exportdialog.ui \
|
||||
dialogs/preferencesdialog.ui \
|
||||
dialogs/demonotice.ui
|
||||
|
||||
win32 {
|
||||
RC_FILE = icons/resources.rc
|
||||
LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lopengl32
|
||||
}
|
||||
|
||||
mac {
|
||||
LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample
|
||||
ICON = icons/olive.icns
|
||||
INCLUDEPATH = /usr/local/include
|
||||
}
|
||||
|
||||
linux {
|
||||
LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample
|
||||
}
|
||||
|
||||
RESOURCES += \
|
||||
icons/icons.qrc
|
||||
+11
-5
@@ -119,11 +119,13 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) {
|
||||
}
|
||||
}
|
||||
|
||||
void LabelSlider::mouseMoveEvent(QMouseEvent*) {
|
||||
void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
|
||||
if (drag_start) {
|
||||
drag_proc = true;
|
||||
int diff = (cursor().pos().x()-drag_start_x) + (drag_start_y-cursor().pos().y());
|
||||
set_value(internal_value + ((display_type == LABELSLIDER_PERCENT) ? (diff*0.01) : diff), true);
|
||||
double diff = (cursor().pos().x()-drag_start_x) + (drag_start_y-cursor().pos().y());
|
||||
if (event->modifiers() & Qt::ControlModifier) diff *= 0.01;
|
||||
if (display_type == LABELSLIDER_PERCENT) diff *= 0.01;
|
||||
set_value(internal_value + diff, true);
|
||||
cursor().setPos(drag_start_x, drag_start_y);
|
||||
}
|
||||
}
|
||||
@@ -146,8 +148,10 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
|
||||
QLineEdit::Normal,
|
||||
valueToString(internal_value)
|
||||
);
|
||||
if (s.isEmpty()) return;
|
||||
d = timecode_to_frame(s, config.timecode_view, frame_rate); // string to frame number
|
||||
} else {
|
||||
bool ok;
|
||||
d = QInputDialog::getDouble(
|
||||
this,
|
||||
"Set Value",
|
||||
@@ -155,9 +159,11 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) {
|
||||
(display_type == LABELSLIDER_PERCENT) ? internal_value * 100 : internal_value,
|
||||
(min_enabled) ? min_value : INT_MIN,
|
||||
(max_enabled) ? max_value : INT_MAX,
|
||||
decimal_places
|
||||
decimal_places,
|
||||
&ok
|
||||
);
|
||||
if (display_type == LABELSLIDER_PERCENT) d *= 0.01;
|
||||
if (!ok) return;
|
||||
if (display_type == LABELSLIDER_PERCENT) d *= 0.01;
|
||||
}
|
||||
if (d != internal_value) {
|
||||
previous_value = internal_value;
|
||||
|
||||
+178
-135
@@ -594,30 +594,28 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
|
||||
panel_timeline->deselect_area(link->timeline_in, link->timeline_out, link->track);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (panel_timeline->transition_select != TA_NO_TRANSITION) {
|
||||
panel_timeline->deselect_area(clip->timeline_in, clip->timeline_out, clip->track);
|
||||
} else if (panel_timeline->tool == TIMELINE_TOOL_POINTER && panel_timeline->transition_select != TA_NO_TRANSITION) {
|
||||
panel_timeline->deselect_area(clip->timeline_in, clip->timeline_out, clip->track);
|
||||
|
||||
for (int i=0;i<clip->linked.size();i++) {
|
||||
Clip* link = sequence->clips.at(clip->linked.at(i));
|
||||
panel_timeline->deselect_area(link->timeline_in, link->timeline_out, link->track);
|
||||
}
|
||||
for (int i=0;i<clip->linked.size();i++) {
|
||||
Clip* link = sequence->clips.at(clip->linked.at(i));
|
||||
panel_timeline->deselect_area(link->timeline_in, link->timeline_out, link->track);
|
||||
}
|
||||
|
||||
Selection s;
|
||||
s.track = clip->track;
|
||||
Selection s;
|
||||
s.track = clip->track;
|
||||
|
||||
if (panel_timeline->transition_select == TA_OPENING_TRANSITION && clip->get_opening_transition() != NULL) {
|
||||
s.in = clip->timeline_in;
|
||||
if (clip->get_opening_transition()->secondary_clip != NULL) s.in -= clip->get_opening_transition()->length;
|
||||
s.out = clip->timeline_in + clip->get_opening_transition()->length;
|
||||
} else if (panel_timeline->transition_select == TA_CLOSING_TRANSITION && clip->get_closing_transition() != NULL) {
|
||||
s.in = clip->timeline_out - clip->get_closing_transition()->length;
|
||||
s.out = clip->timeline_out;
|
||||
if (clip->get_closing_transition()->secondary_clip != NULL) s.out += clip->get_closing_transition()->length;
|
||||
}
|
||||
sequence->selections.append(s);
|
||||
}
|
||||
}
|
||||
if (panel_timeline->transition_select == TA_OPENING_TRANSITION && clip->get_opening_transition() != NULL) {
|
||||
s.in = clip->timeline_in;
|
||||
if (clip->get_opening_transition()->secondary_clip != NULL) s.in -= clip->get_opening_transition()->get_true_length();
|
||||
s.out = clip->timeline_in + clip->get_opening_transition()->get_true_length();
|
||||
} else if (panel_timeline->transition_select == TA_CLOSING_TRANSITION && clip->get_closing_transition() != NULL) {
|
||||
s.in = clip->timeline_out - clip->get_closing_transition()->get_true_length();
|
||||
s.out = clip->timeline_out;
|
||||
if (clip->get_closing_transition()->secondary_clip != NULL) s.out += clip->get_closing_transition()->get_true_length();
|
||||
}
|
||||
sequence->selections.append(s);
|
||||
}
|
||||
} else {
|
||||
// if "shift" is not down
|
||||
if (!shift) {
|
||||
@@ -629,15 +627,17 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) {
|
||||
s.in = clip->timeline_in;
|
||||
s.out = clip->timeline_out;
|
||||
|
||||
if (panel_timeline->transition_select == TA_OPENING_TRANSITION) {
|
||||
s.out = clip->timeline_in + clip->get_opening_transition()->length;
|
||||
if (clip->get_opening_transition()->secondary_clip != NULL) s.in -= clip->get_opening_transition()->length;
|
||||
}
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_POINTER) {
|
||||
if (panel_timeline->transition_select == TA_OPENING_TRANSITION) {
|
||||
s.out = clip->timeline_in + clip->get_opening_transition()->get_true_length();
|
||||
if (clip->get_opening_transition()->secondary_clip != NULL) s.in -= clip->get_opening_transition()->get_true_length();
|
||||
}
|
||||
|
||||
if (panel_timeline->transition_select == TA_CLOSING_TRANSITION) {
|
||||
s.in = clip->timeline_out - clip->get_closing_transition()->length;
|
||||
if (clip->get_closing_transition()->secondary_clip != NULL) s.out += clip->get_closing_transition()->length;
|
||||
}
|
||||
if (panel_timeline->transition_select == TA_CLOSING_TRANSITION) {
|
||||
s.in = clip->timeline_out - clip->get_closing_transition()->get_true_length();
|
||||
if (clip->get_closing_transition()->secondary_clip != NULL) s.out += clip->get_closing_transition()->get_true_length();
|
||||
}
|
||||
}
|
||||
|
||||
s.track = clip->track;
|
||||
sequence->selections.append(s);
|
||||
@@ -707,7 +707,7 @@ void make_room_for_transition(ComboAction* ca, Clip* c, int type, long transitio
|
||||
if (c->get_closing_transition() != NULL) {
|
||||
if (transition_end >= c->timeline_out) {
|
||||
ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION));
|
||||
} else if (transition_end > c->timeline_out - c->get_closing_transition()->length) {
|
||||
} else if (transition_end > c->timeline_out - c->get_closing_transition()->get_true_length()) {
|
||||
ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, c->timeline_out - transition_end));
|
||||
}
|
||||
}
|
||||
@@ -718,7 +718,7 @@ void make_room_for_transition(ComboAction* ca, Clip* c, int type, long transitio
|
||||
if (c->get_opening_transition() != NULL) {
|
||||
if (transition_start <= c->timeline_in) {
|
||||
ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION));
|
||||
} else if (transition_start < c->timeline_in + c->get_opening_transition()->length) {
|
||||
} else if (transition_start < c->timeline_in + c->get_opening_transition()->get_true_length()) {
|
||||
ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, transition_start - c->timeline_in));
|
||||
}
|
||||
}
|
||||
@@ -772,41 +772,41 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
|
||||
if (c->track < 0) {
|
||||
// default video effects (before custom effects)
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TRANSFORM)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT)));
|
||||
c->media_type = MEDIA_TYPE_SOLID;
|
||||
}
|
||||
|
||||
switch (panel_timeline->creating_object) {
|
||||
case ADD_OBJ_TITLE:
|
||||
c->name = "Title";
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TEXT)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TEXT, EFFECT_TYPE_EFFECT)));
|
||||
break;
|
||||
case ADD_OBJ_SOLID:
|
||||
c->name = "Solid Color";
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_SOLID)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT)));
|
||||
break;
|
||||
case ADD_OBJ_BARS:
|
||||
{
|
||||
c->name = "Bars";
|
||||
Effect* e = create_effect(c, get_internal_meta(EFFECT_INTERNAL_SOLID));
|
||||
Effect* e = create_effect(c, get_internal_meta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT));
|
||||
e->row(0)->field(0)->set_combo_index(1);
|
||||
c->effects.append(e);
|
||||
}
|
||||
break;
|
||||
case ADD_OBJ_TONE:
|
||||
c->name = "Tone";
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TONE)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_TONE, EFFECT_TYPE_EFFECT)));
|
||||
break;
|
||||
case ADD_OBJ_NOISE:
|
||||
c->name = "Noise";
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_NOISE)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_NOISE, EFFECT_TYPE_EFFECT)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (c->track >= 0) {
|
||||
// default audio effects (after custom effects)
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_VOLUME)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_PAN)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT)));
|
||||
c->effects.append(create_effect(c, get_internal_meta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT)));
|
||||
c->media_type = MEDIA_TYPE_TONE;
|
||||
}
|
||||
|
||||
@@ -934,29 +934,29 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
// step 3 - move clips
|
||||
Clip* c = sequence->clips.at(g.clip);
|
||||
if (g.transition == NULL) {
|
||||
ca->append(new MoveClipAction(c, c->timeline_in + (g.in - g.old_in), c->timeline_out + (g.out - g.old_out), c->clip_in + (g.clip_in - g.old_clip_in), c->track + (g.track - g.old_track)));
|
||||
move_clip(ca, c, c->timeline_in + (g.in - g.old_in), c->timeline_out + (g.out - g.old_out), c->clip_in + (g.clip_in - g.old_clip_in), c->track + (g.track - g.old_track));
|
||||
|
||||
// adjust transitions if we need to
|
||||
long new_clip_length = (g.out - g.in);
|
||||
if (c->get_opening_transition() != NULL) {
|
||||
long max_open_length = new_clip_length;
|
||||
if (c->get_closing_transition() != NULL && !panel_timeline->trim_in_point) {
|
||||
max_open_length -= c->get_closing_transition()->length;
|
||||
max_open_length -= c->get_closing_transition()->get_true_length();
|
||||
}
|
||||
if (max_open_length <= 0) {
|
||||
ca->append(new DeleteTransitionCommand(c, TA_OPENING_TRANSITION));
|
||||
} else if (c->get_opening_transition()->length > max_open_length) {
|
||||
} else if (c->get_opening_transition()->get_true_length() > max_open_length) {
|
||||
ca->append(new ModifyTransitionCommand(c, TA_OPENING_TRANSITION, max_open_length));
|
||||
}
|
||||
}
|
||||
if (c->get_closing_transition() != NULL) {
|
||||
long max_open_length = new_clip_length;
|
||||
if (c->get_opening_transition() != NULL && panel_timeline->trim_in_point) {
|
||||
max_open_length -= c->get_opening_transition()->length;
|
||||
max_open_length -= c->get_opening_transition()->get_true_length();
|
||||
}
|
||||
if (max_open_length <= 0) {
|
||||
ca->append(new DeleteTransitionCommand(c, TA_CLOSING_TRANSITION));
|
||||
} else if (c->get_closing_transition()->length > max_open_length) {
|
||||
} else if (c->get_closing_transition()->get_true_length() > max_open_length) {
|
||||
ca->append(new ModifyTransitionCommand(c, TA_CLOSING_TRANSITION, max_open_length));
|
||||
}
|
||||
}
|
||||
@@ -971,13 +971,13 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
if (g.transition->secondary_clip != NULL) {
|
||||
if (g.in != g.old_in && !g.trimming) {
|
||||
long movement = g.in - g.old_in;
|
||||
ca->append(new MoveClipAction(g.transition->parent_clip, g.transition->parent_clip->timeline_in + movement, g.transition->parent_clip->timeline_out, g.transition->parent_clip->clip_in + movement, g.transition->parent_clip->track));
|
||||
ca->append(new MoveClipAction(g.transition->secondary_clip, g.transition->secondary_clip->timeline_in, g.transition->secondary_clip->timeline_out + movement, g.transition->secondary_clip->clip_in, g.transition->secondary_clip->track));
|
||||
move_clip(ca, g.transition->parent_clip, g.transition->parent_clip->timeline_in + movement, g.transition->parent_clip->timeline_out, g.transition->parent_clip->clip_in + movement, g.transition->parent_clip->track, false);
|
||||
move_clip(ca, g.transition->secondary_clip, g.transition->secondary_clip->timeline_in, g.transition->secondary_clip->timeline_out + movement, g.transition->secondary_clip->clip_in, g.transition->secondary_clip->track, false);
|
||||
}
|
||||
} else if (is_opening_transition) {
|
||||
if (g.in != g.old_in) {
|
||||
// if transition is going to make the clip bigger, make the clip bigger
|
||||
ca->append(new MoveClipAction(c, c->timeline_in + (g.in - g.old_in), c->timeline_out, c->clip_in + (g.clip_in - g.old_clip_in), c->track));
|
||||
move_clip(ca, c, c->timeline_in + (g.in - g.old_in), c->timeline_out, c->clip_in + (g.clip_in - g.old_clip_in), c->track);
|
||||
clip_length -= (g.in - g.old_in);
|
||||
}
|
||||
|
||||
@@ -985,7 +985,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
} else {
|
||||
if (g.out != g.old_out) {
|
||||
// if transition is going to make the clip bigger, make the clip bigger
|
||||
ca->append(new MoveClipAction(c, c->timeline_in, c->timeline_out + (g.out - g.old_out), c->clip_in, c->track));
|
||||
move_clip(ca, c, c->timeline_in, c->timeline_out + (g.out - g.old_out), c->clip_in, c->track);
|
||||
clip_length += (g.out - g.old_out);
|
||||
}
|
||||
|
||||
@@ -1001,16 +1001,16 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
const Ghost& g = panel_timeline->ghosts.at(0);
|
||||
|
||||
if (g.in != g.out) {
|
||||
Clip* c = sequence->clips.at(g.clip);
|
||||
|
||||
long transition_start = qMin(g.in, g.out);
|
||||
long transition_end = qMax(g.in, g.out);
|
||||
|
||||
make_room_for_transition(ca, c, panel_timeline->transition_tool_type, transition_start, transition_end, true);
|
||||
Clip* pre = sequence->clips.at(g.clip);
|
||||
Clip* post = pre;
|
||||
|
||||
make_room_for_transition(ca, pre, panel_timeline->transition_tool_type, transition_start, transition_end, true);
|
||||
|
||||
if (panel_timeline->transition_tool_post_clip > -1) {
|
||||
Clip* pre = c;
|
||||
Clip* post = sequence->clips.at(panel_timeline->transition_tool_post_clip);
|
||||
post = sequence->clips.at(panel_timeline->transition_tool_post_clip);
|
||||
int opposite_type = (panel_timeline->transition_tool_type == TA_OPENING_TRANSITION) ? TA_CLOSING_TRANSITION : TA_OPENING_TRANSITION;
|
||||
make_room_for_transition(
|
||||
ca,
|
||||
@@ -1020,33 +1020,47 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
transition_end,
|
||||
true
|
||||
);
|
||||
|
||||
if (panel_timeline->transition_tool_type == TA_CLOSING_TRANSITION) {
|
||||
// swap
|
||||
Clip* temp = pre;
|
||||
pre = post;
|
||||
post = temp;
|
||||
}
|
||||
ca->append(new AddTransitionCommand(pre, post, panel_timeline->transition_tool_meta, TA_OPENING_TRANSITION, transition_end - pre->timeline_in));
|
||||
} else {
|
||||
if (transition_start < c->timeline_in || transition_end > c->timeline_out) {
|
||||
// delete shit over there and extend timeline in
|
||||
QVector<Selection> areas;
|
||||
Selection s;
|
||||
if (transition_start < c->timeline_in) {
|
||||
s.in = transition_start;
|
||||
s.out = c->timeline_in;
|
||||
} else if (transition_end > c->timeline_out) {
|
||||
s.in = c->timeline_out;
|
||||
s.out = transition_end;
|
||||
}
|
||||
s.track = c->track;
|
||||
areas.append(s);
|
||||
}
|
||||
|
||||
panel_timeline->delete_areas_and_relink(ca, areas);
|
||||
ca->append(new MoveClipAction(c, qMin(transition_start, c->timeline_in), qMax(transition_end, c->timeline_out), c->clip_in, c->track));
|
||||
if (transition_start < post->timeline_in || transition_end > pre->timeline_out) {
|
||||
// delete shit over there and extend timeline in
|
||||
QVector<Selection> areas;
|
||||
Selection s;
|
||||
s.track = post->track;
|
||||
|
||||
bool move_post = false;
|
||||
bool move_pre = false;
|
||||
|
||||
if (transition_start < post->timeline_in) {
|
||||
s.in = transition_start;
|
||||
s.out = post->timeline_in;
|
||||
areas.append(s);
|
||||
move_post = true;
|
||||
}
|
||||
if (transition_end > pre->timeline_out) {
|
||||
s.in = pre->timeline_out;
|
||||
s.out = transition_end;
|
||||
areas.append(s);
|
||||
move_pre = true;
|
||||
}
|
||||
|
||||
ca->append(new AddTransitionCommand(c, NULL, panel_timeline->transition_tool_meta, panel_timeline->transition_tool_type, transition_end - transition_start));
|
||||
panel_timeline->delete_areas_and_relink(ca, areas);
|
||||
|
||||
if (move_post) move_clip(ca, post, qMin(transition_start, post->timeline_in), post->timeline_out, post->clip_in - (post->timeline_in - transition_start), post->track);
|
||||
if (move_pre) move_clip(ca, pre, pre->timeline_in, qMax(transition_end, pre->timeline_out), pre->clip_in, pre->track);
|
||||
}
|
||||
|
||||
if (panel_timeline->transition_tool_post_clip > -1) {
|
||||
ca->append(new AddTransitionCommand(pre, post, NULL, panel_timeline->transition_tool_meta, TA_OPENING_TRANSITION, transition_end - pre->timeline_in));
|
||||
} else {
|
||||
ca->append(new AddTransitionCommand(pre, NULL, NULL, panel_timeline->transition_tool_meta, panel_timeline->transition_tool_type, transition_end - transition_start));
|
||||
}
|
||||
|
||||
push_undo = true;
|
||||
@@ -1110,9 +1124,14 @@ void TimelineWidget::init_ghosts() {
|
||||
Clip* c = sequence->clips.at(g.clip);
|
||||
|
||||
g.track = g.old_track = c->track;
|
||||
g.clip_in = g.old_clip_in = panel_timeline->tool == TIMELINE_TOOL_SLIP ? c->get_clip_in_with_transition() : c->clip_in;
|
||||
g.clip_in = g.old_clip_in = c->clip_in;
|
||||
|
||||
if (g.transition == NULL) {
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_SLIP) {
|
||||
g.clip_in = g.old_clip_in = c->get_clip_in_with_transition();
|
||||
g.in = g.old_in = c->get_timeline_in_with_transition();
|
||||
g.out = g.old_out = c->get_timeline_out_with_transition();
|
||||
g.ghost_length = g.old_out - g.old_in;
|
||||
} else if (g.transition == NULL) {
|
||||
// this ghost is for a clip
|
||||
g.in = g.old_in = c->timeline_in;
|
||||
g.out = g.old_out = c->timeline_out;
|
||||
@@ -1125,7 +1144,7 @@ void TimelineWidget::init_ghosts() {
|
||||
g.out = g.old_out = c->get_timeline_out_with_transition();
|
||||
g.ghost_length = c->get_closing_transition()->get_length();
|
||||
g.in = g.old_in = g.out - g.ghost_length;
|
||||
g.clip_in = g.old_clip_in = c->clip_in + c->getLength() - c->get_closing_transition()->length;
|
||||
g.clip_in = g.old_clip_in = c->clip_in + c->getLength() - c->get_closing_transition()->get_true_length();
|
||||
}
|
||||
|
||||
// used for trim ops
|
||||
@@ -1139,6 +1158,42 @@ void TimelineWidget::init_ghosts() {
|
||||
}
|
||||
}
|
||||
|
||||
void validate_transitions(Clip* otc, Clip* ctc, long length, long& frame_diff) {
|
||||
long validator;
|
||||
if (otc != NULL) {
|
||||
validator = otc->timeline_in + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator; // prevent from going below 0 on the timeline
|
||||
|
||||
if (panel_timeline->transition_tool_post_clip > -1) {
|
||||
validator = otc->clip_in + length - frame_diff;
|
||||
if (validator < 0) frame_diff += validator; // prevent from going below 0 for the media
|
||||
|
||||
validator = otc->clip_in + length + frame_diff - otc->getMaximumLength();
|
||||
if (validator > 0) frame_diff -= validator; // prevent transition from exceeding media length
|
||||
} else {
|
||||
validator = otc->clip_in + length + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator; // prevent from going below 0 for the media
|
||||
if (validator > otc->getMaximumLength()) frame_diff -= (validator - otc->getMaximumLength()); // prevent transition from exceeding media length
|
||||
}
|
||||
}
|
||||
|
||||
if (ctc != NULL) {
|
||||
// prevent transition from exceeding media length
|
||||
validator = ctc->clip_in + length + ctc->getLength() + frame_diff;
|
||||
if (validator > ctc->getMaximumLength()) frame_diff -= (validator - ctc->getMaximumLength());
|
||||
|
||||
// prevent from going below 0 for the media
|
||||
if (panel_timeline->transition_tool_post_clip > -1) {
|
||||
validator = ctc->clip_in + length - ctc->getLength() + frame_diff;
|
||||
if (validator > 0) frame_diff -= validator;
|
||||
}
|
||||
|
||||
// prevent from going below 0 on the timeline
|
||||
validator = ctc->timeline_out + length + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator;
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
int mouse_track = getTrackFromScreenPoint(mouse_pos.y());
|
||||
long frame_diff = (lock_frame) ? 0 : panel_timeline->getTimelineFrameFromScreenPoint(mouse_pos.x()) - panel_timeline->drag_frame_start;
|
||||
@@ -1229,17 +1284,18 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
// prevent dual transition from going below 0 on the primary or media length on the secondary
|
||||
if (g.transition != NULL && g.transition->secondary_clip != NULL) {
|
||||
if (g.trim_in) {
|
||||
validator = g.transition->parent_clip->get_clip_in_with_transition() + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator;
|
||||
frame_diff = -frame_diff;
|
||||
}
|
||||
|
||||
validator = g.transition->secondary_clip->get_timeline_out_with_transition() - g.transition->secondary_clip->get_timeline_in_with_transition() + g.transition->secondary_clip->get_clip_in_with_transition() - frame_diff - g.transition->secondary_clip->getMaximumLength();
|
||||
if (validator > 0) frame_diff += validator;
|
||||
} else {
|
||||
validator = g.transition->parent_clip->get_clip_in_with_transition() - frame_diff;
|
||||
if (validator < 0) frame_diff += validator;
|
||||
// TESTING CODE
|
||||
Clip* otc = g.transition->parent_clip;
|
||||
Clip* ctc = g.transition->secondary_clip;
|
||||
|
||||
validator = g.transition->secondary_clip->get_timeline_out_with_transition() - g.transition->secondary_clip->get_timeline_in_with_transition() + g.transition->secondary_clip->get_clip_in_with_transition() + frame_diff - g.transition->secondary_clip->getMaximumLength();
|
||||
if (validator > 0) frame_diff -= validator;
|
||||
validate_transitions(otc, ctc, g.transition->get_true_length(), frame_diff);
|
||||
// TESTING CODE END
|
||||
|
||||
if (g.trim_in) {
|
||||
frame_diff = -frame_diff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1277,9 +1333,16 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
if (g.transition != NULL) {
|
||||
if (g.transition->secondary_clip != NULL) {
|
||||
// prevent dual transitions from going below 0 on the primary or above media length on the secondary
|
||||
|
||||
validator = g.transition->parent_clip->get_clip_in_with_transition() + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator;
|
||||
|
||||
validator = g.transition->secondary_clip->get_timeline_out_with_transition() - g.transition->secondary_clip->get_timeline_in_with_transition() - g.transition->get_length() + g.transition->secondary_clip->get_clip_in_with_transition() + frame_diff;
|
||||
if (validator < 0) frame_diff -= validator;
|
||||
|
||||
validator = g.transition->parent_clip->clip_in + frame_diff - g.transition->parent_clip->getMaximumLength() + g.transition->get_true_length();
|
||||
if (validator > 0) frame_diff -= validator;
|
||||
|
||||
validator = g.transition->secondary_clip->get_timeline_out_with_transition() - g.transition->secondary_clip->get_timeline_in_with_transition() + g.transition->secondary_clip->get_clip_in_with_transition() + frame_diff - g.transition->secondary_clip->getMaximumLength();
|
||||
if (validator > 0) frame_diff -= validator;
|
||||
} else {
|
||||
@@ -1310,6 +1373,13 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
}
|
||||
}
|
||||
} else if (panel_timeline->tool == TIMELINE_TOOL_TRANSITION) {
|
||||
bool flipped = false;
|
||||
|
||||
if (frame_diff < 0 && panel_timeline->transition_tool_post_clip > -1) {
|
||||
frame_diff = -frame_diff;
|
||||
flipped = true;
|
||||
}
|
||||
|
||||
Clip* otc = c; // open transition clip
|
||||
Clip* ctc = (panel_timeline->transition_tool_post_clip > -1) ? sequence->clips.at(panel_timeline->transition_tool_post_clip) : NULL; // close transition clip
|
||||
|
||||
@@ -1320,36 +1390,10 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
ctc = temp;
|
||||
}
|
||||
|
||||
if (otc != NULL) {
|
||||
validator = otc->timeline_in + frame_diff;
|
||||
if (validator < 0) { // prevent from going below 0 on the timeline
|
||||
frame_diff -= validator;
|
||||
}
|
||||
validate_transitions(otc, ctc, 0, frame_diff);
|
||||
|
||||
validator = otc->clip_in - frame_diff;
|
||||
if (validator < 0) { // prevent from going below 0 for the media
|
||||
frame_diff += validator;
|
||||
}
|
||||
|
||||
if (validator > otc->getMaximumLength()) { // prevent transition from exceeding media length
|
||||
frame_diff -= (validator - otc->getMaximumLength());
|
||||
}
|
||||
}
|
||||
|
||||
if (ctc != NULL) {
|
||||
validator = ctc->clip_in + ctc->getLength() + frame_diff; // prevent transition from exceeding media length
|
||||
if (validator > ctc->getMaximumLength()) {
|
||||
frame_diff -= (validator - ctc->getMaximumLength());
|
||||
}
|
||||
|
||||
if (validator < 0) { // prevent from going below 0 for the media
|
||||
frame_diff -= validator;
|
||||
}
|
||||
|
||||
validator = ctc->timeline_out + frame_diff; // prevent from going below 0 on the timeline
|
||||
if (validator < 0) {
|
||||
frame_diff -= validator;
|
||||
}
|
||||
if (flipped) {
|
||||
frame_diff = -frame_diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1460,7 +1504,7 @@ void TimelineWidget::update_ghosts(const QPoint& mouse_pos, bool lock_frame) {
|
||||
|
||||
if (panel_timeline->importing) {
|
||||
QToolTip::showText(mapToGlobal(mouse_pos), frame_to_timecode(earliest_in_point, config.timecode_view, sequence->frame_rate));
|
||||
} else {
|
||||
} else {
|
||||
QString tip = ((frame_diff < 0) ? "-" : "+") + frame_to_timecode(qAbs(frame_diff), config.timecode_view, sequence->frame_rate);
|
||||
if (panel_timeline->trim_target > -1) {
|
||||
// find which clip is being moved
|
||||
@@ -1585,22 +1629,16 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
bool add = panel_timeline->is_clip_selected(c, true);
|
||||
|
||||
// if a whole clip is not selected, maybe just a transition is
|
||||
if (!add && panel_timeline->tool == TIMELINE_TOOL_POINTER && (c->get_opening_transition() != NULL || c->get_closing_transition() != NULL)) {
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_POINTER && (c->get_opening_transition() != NULL || c->get_closing_transition() != NULL)) {
|
||||
// check if any selections contain the whole clip or transition
|
||||
for (int j=0;j<sequence->selections.size();j++) {
|
||||
const Selection& s = sequence->selections.at(j);
|
||||
if (s.track == c->track) {
|
||||
if (c->get_opening_transition() != NULL
|
||||
&& s.out == c->timeline_in + c->get_opening_transition()->length
|
||||
&& ((c->get_opening_transition()->secondary_clip == NULL && s.in == c->timeline_in)
|
||||
|| (c->get_opening_transition()->secondary_clip != NULL && s.in == c->timeline_in - c->get_opening_transition()->length))) {
|
||||
if (selection_contains_transition(s, c, TA_OPENING_TRANSITION)) {
|
||||
g.transition = c->get_opening_transition();
|
||||
add = true;
|
||||
break;
|
||||
} else if (c->get_closing_transition() != NULL
|
||||
&& s.in == c->timeline_out - c->get_closing_transition()->length
|
||||
&& ((c->get_closing_transition()->secondary_clip == NULL && s.out == c->timeline_out)
|
||||
|| (c->get_closing_transition()->secondary_clip != NULL && s.out == c->timeline_out + c->get_closing_transition()->length))) {
|
||||
} else if (selection_contains_transition(s, c, TA_CLOSING_TRANSITION)) {
|
||||
g.transition = c->get_closing_transition();
|
||||
add = true;
|
||||
break;
|
||||
@@ -1769,7 +1807,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
|
||||
panel_timeline->moving_proc = true;
|
||||
}
|
||||
update_ui(true);
|
||||
update_ui(false);
|
||||
} else if (panel_timeline->splitting) {
|
||||
int track_start = qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start);
|
||||
int track_end = qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start);
|
||||
@@ -1793,7 +1831,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
update_ui(true);
|
||||
update_ui(false);
|
||||
} else if (panel_timeline->rect_select_init) {
|
||||
if (panel_timeline->rect_select_proc) {
|
||||
panel_timeline->rect_select_w = event->pos().x() - panel_timeline->rect_select_x;
|
||||
@@ -1897,9 +1935,9 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
tooltip_timer.start();
|
||||
tooltip_clip = i;
|
||||
|
||||
if (c->get_opening_transition() != NULL && panel_timeline->cursor_frame <= c->timeline_in + c->get_opening_transition()->length) {
|
||||
if (c->get_opening_transition() != NULL && panel_timeline->cursor_frame <= c->timeline_in + c->get_opening_transition()->get_true_length()) {
|
||||
panel_timeline->transition_select = TA_OPENING_TRANSITION;
|
||||
} else if (c->get_closing_transition() != NULL && panel_timeline->cursor_frame >= c->timeline_out - c->get_closing_transition()->length) {
|
||||
} else if (c->get_closing_transition() != NULL && panel_timeline->cursor_frame >= c->timeline_out - c->get_closing_transition()->get_true_length()) {
|
||||
panel_timeline->transition_select = TA_CLOSING_TRANSITION;
|
||||
}
|
||||
}
|
||||
@@ -1923,7 +1961,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
}
|
||||
if (panel_timeline->tool == TIMELINE_TOOL_POINTER) {
|
||||
if (c->get_opening_transition() != NULL) {
|
||||
long transition_point = c->timeline_in + c->get_opening_transition()->length;
|
||||
long transition_point = c->timeline_in + c->get_opening_transition()->get_true_length();
|
||||
|
||||
if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) {
|
||||
int nc = qAbs(transition_point - 1 - panel_timeline->cursor_frame);
|
||||
@@ -1937,7 +1975,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
|
||||
}
|
||||
}
|
||||
if (c->get_closing_transition() != NULL) {
|
||||
long transition_point = c->timeline_out - c->get_closing_transition()->length;
|
||||
long transition_point = c->timeline_out - c->get_closing_transition()->get_true_length();
|
||||
if (transition_point > mouse_frame_lower && transition_point < mouse_frame_upper) {
|
||||
int nc = qAbs(transition_point + 1 - panel_timeline->cursor_frame);
|
||||
if (nc < closeness) {
|
||||
@@ -2091,7 +2129,7 @@ void draw_transition(QPainter& p, Clip* c, const QRect& clip_rect, QRect& text_r
|
||||
Transition* t = (transition_type == TA_OPENING_TRANSITION) ? c->get_opening_transition() : c->get_closing_transition();
|
||||
if (t != NULL) {
|
||||
QColor transition_color(255, 0, 0, 16);
|
||||
int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->length);
|
||||
int transition_width = getScreenPointFromFrame(panel_timeline->zoom, t->get_true_length());
|
||||
int transition_height = clip_rect.height();
|
||||
int tr_y = clip_rect.y();
|
||||
int tr_x = 0;
|
||||
@@ -2106,6 +2144,8 @@ void draw_transition(QPainter& p, Clip* c, const QRect& clip_rect, QRect& text_r
|
||||
p.fillRect(transition_rect, transition_color);
|
||||
QRect transition_text_rect(transition_rect.x() + CLIP_TEXT_PADDING, transition_rect.y() + CLIP_TEXT_PADDING, transition_rect.width() - CLIP_TEXT_PADDING, transition_rect.height() - CLIP_TEXT_PADDING);
|
||||
if (transition_text_rect.width() > MAX_TEXT_WIDTH) {
|
||||
bool draw_text = true;
|
||||
|
||||
p.setPen(QColor(0, 0, 0, 96));
|
||||
if (t->secondary_clip == NULL) {
|
||||
if (transition_type == TA_OPENING_TRANSITION) {
|
||||
@@ -2113,18 +2153,21 @@ void draw_transition(QPainter& p, Clip* c, const QRect& clip_rect, QRect& text_r
|
||||
} else {
|
||||
p.drawLine(transition_rect.topLeft(), transition_rect.bottomRight());
|
||||
}
|
||||
} else{
|
||||
} else {
|
||||
if (transition_type == TA_OPENING_TRANSITION) {
|
||||
p.drawLine(QPoint(transition_rect.left(), transition_rect.center().y()), transition_rect.topRight());
|
||||
p.drawLine(QPoint(transition_rect.left(), transition_rect.center().y()), transition_rect.bottomRight());
|
||||
draw_text = false;
|
||||
} else {
|
||||
p.drawLine(QPoint(transition_rect.right(), transition_rect.center().y()), transition_rect.topLeft());
|
||||
p.drawLine(QPoint(transition_rect.right(), transition_rect.center().y()), transition_rect.bottomLeft());
|
||||
}
|
||||
}
|
||||
|
||||
p.setPen(Qt::white);
|
||||
p.drawText(transition_text_rect, 0, t->name, &transition_text_rect);
|
||||
if (draw_text) {
|
||||
p.setPen(Qt::white);
|
||||
p.drawText(transition_text_rect, 0, t->meta->name, &transition_text_rect);
|
||||
}
|
||||
}
|
||||
p.setPen(Qt::black);
|
||||
p.drawRect(transition_rect);
|
||||
@@ -2231,12 +2274,12 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
|
||||
if (thumb_x < width() && thumb_y < height()) {
|
||||
int space_for_thumb = clip_rect.width()-1;
|
||||
if (clip->get_opening_transition() != NULL) {
|
||||
int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->get_opening_transition()->length);
|
||||
int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->get_opening_transition()->get_true_length());
|
||||
thumb_x += ot_width;
|
||||
space_for_thumb -= ot_width;
|
||||
}
|
||||
if (clip->get_closing_transition() != NULL) {
|
||||
space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->get_closing_transition()->length);
|
||||
space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->get_closing_transition()->get_true_length());
|
||||
}
|
||||
int thumb_height = clip_rect.height()-thumb_y;
|
||||
int thumb_width = (thumb_height*((double)ms->video_preview.width()/(double)ms->video_preview.height()));
|
||||
@@ -2245,7 +2288,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
|
||||
&& thumb_y + thumb_height >= 0
|
||||
&& space_for_thumb > MAX_TEXT_WIDTH) {
|
||||
int thumb_clip_width = qMin(thumb_width, space_for_thumb);
|
||||
p.drawPixmap(QRect(thumb_x, clip_rect.y()+thumb_y, thumb_clip_width, thumb_height), ms->video_preview, QRect(0, 0, thumb_clip_width*((double)ms->video_preview.width()/(double)thumb_width), ms->video_preview.height()));
|
||||
p.drawImage(QRect(thumb_x, clip_rect.y()+thumb_y, thumb_clip_width, thumb_height), ms->video_preview, QRect(0, 0, thumb_clip_width*((double)ms->video_preview.width()/(double)thumb_width), ms->video_preview.height()));
|
||||
}
|
||||
}
|
||||
} else if (clip_rect.height() > TRACK_MIN_HEIGHT) {
|
||||
|
||||
+220
-56
@@ -16,30 +16,36 @@
|
||||
#include "io/config.h"
|
||||
#include "debug.h"
|
||||
#include "io/math.h"
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "project/undo.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QAudioOutput>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QtMath>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QMouseEvent>
|
||||
#include <QMimeData>
|
||||
#include <QDrag>
|
||||
#include <QMenu>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QFileDialog>
|
||||
#include <QPolygon>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#define GL_DEFAULT_BLEND glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
|
||||
|
||||
ViewerWidget::ViewerWidget(QWidget *parent) :
|
||||
QOpenGLWidget(parent),
|
||||
default_fbo(NULL),
|
||||
waveform(false),
|
||||
dragging(false)
|
||||
dragging(false),
|
||||
selected_gizmo(NULL)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
QSurfaceFormat format;
|
||||
@@ -109,6 +115,8 @@ void ViewerWidget::retry() {
|
||||
}
|
||||
|
||||
void ViewerWidget::initializeGL() {
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(delete_function()), Qt::DirectConnection);
|
||||
|
||||
retry_timer.start();
|
||||
@@ -129,27 +137,103 @@ void ViewerWidget::seek_from_click(int x) {
|
||||
viewer->seek(getFrameFromScreenPoint((double) width() / (double) waveform_clip->timeline_out, x));
|
||||
}
|
||||
|
||||
double get_timecode(Clip* c, long playhead) {
|
||||
return ((double)(playhead-c->get_timeline_in_with_transition()+c->get_clip_in_with_transition())/(double)c->sequence->frame_rate);
|
||||
}
|
||||
|
||||
EffectGizmo* ViewerWidget::get_gizmo_from_mouse(int x, int y) {
|
||||
if (gizmos != NULL) {
|
||||
double multiplier = (double) viewer->seq->width / (double) width();
|
||||
QPoint mouse_pos(qRound(x*multiplier), qRound(y*multiplier));
|
||||
int dot_size = 2 * qRound(GIZMO_DOT_SIZE * multiplier);
|
||||
for (int i=0;i<gizmos->gizmo_count();i++) {
|
||||
EffectGizmo* g = gizmos->gizmo(i);
|
||||
|
||||
switch (g->get_type()) {
|
||||
case GIZMO_TYPE_DOT:
|
||||
if (mouse_pos.x() > g->screen_pos[0].x() - dot_size
|
||||
&& mouse_pos.y() > g->screen_pos[0].y() - dot_size
|
||||
&& mouse_pos.x() < g->screen_pos[0].x() + dot_size
|
||||
&& mouse_pos.y() < g->screen_pos[0].y() + dot_size) {
|
||||
return g;
|
||||
}
|
||||
break;
|
||||
case GIZMO_TYPE_POLY:
|
||||
if (QPolygon(g->screen_pos).containsPoint(mouse_pos, Qt::OddEvenFill)) {
|
||||
return g;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ViewerWidget::mousePressEvent(QMouseEvent* event) {
|
||||
if (waveform) seek_from_click(event->x());
|
||||
dragging = true;
|
||||
if (waveform) {
|
||||
seek_from_click(event->x());
|
||||
} else {
|
||||
drag_start_x = event->pos().x();
|
||||
drag_start_y = event->pos().y();
|
||||
|
||||
gizmo_x_mvmt = 0;
|
||||
gizmo_y_mvmt = 0;
|
||||
|
||||
selected_gizmo = get_gizmo_from_mouse(event->pos().x(), event->pos().y());
|
||||
}
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
void ViewerWidget::mouseMoveEvent(QMouseEvent* event) {
|
||||
if (dragging) {
|
||||
if (waveform) {
|
||||
seek_from_click(event->x());
|
||||
} else {
|
||||
} else if (gizmos == NULL) {
|
||||
QDrag* drag = new QDrag(this);
|
||||
QMimeData* mimeData = new QMimeData;
|
||||
mimeData->setText("h"); // QMimeData will fail without some kind of data
|
||||
drag->setMimeData(mimeData);
|
||||
drag->exec();
|
||||
}
|
||||
}
|
||||
dragging = false;
|
||||
} else if (selected_gizmo != NULL) {
|
||||
double multiplier = (double) viewer->seq->width / (double) width();
|
||||
|
||||
int x_movement = (event->pos().x() - drag_start_x)*multiplier;
|
||||
int y_movement = (event->pos().y() - drag_start_y)*multiplier;
|
||||
|
||||
gizmos->gizmo_move(selected_gizmo, x_movement, y_movement, get_timecode(gizmos->parent_clip, gizmos->parent_clip->sequence->playhead));
|
||||
|
||||
gizmo_x_mvmt += x_movement;
|
||||
gizmo_y_mvmt += y_movement;
|
||||
|
||||
drag_start_x = event->pos().x();
|
||||
drag_start_y = event->pos().y();
|
||||
|
||||
gizmos->field_changed();
|
||||
}
|
||||
} else {
|
||||
unsetCursor();
|
||||
EffectGizmo* g = get_gizmo_from_mouse(event->pos().x(), event->pos().y());
|
||||
if (g != NULL) {
|
||||
if (g->get_cursor() > -1) {
|
||||
setCursor(static_cast<enum Qt::CursorShape>(g->get_cursor()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::mouseReleaseEvent(QMouseEvent *) {
|
||||
dragging = false;
|
||||
void ViewerWidget::mouseReleaseEvent(QMouseEvent *event) {
|
||||
if (selected_gizmo != NULL) {
|
||||
undo_stack.push(new MoveGizmo(
|
||||
gizmos,
|
||||
selected_gizmo,
|
||||
gizmo_x_mvmt,
|
||||
gizmo_y_mvmt,
|
||||
get_timecode(gizmos->parent_clip, gizmos->parent_clip->sequence->playhead)
|
||||
));
|
||||
}
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
void ViewerWidget::drawTitleSafeArea() {
|
||||
@@ -167,7 +251,7 @@ void ViewerWidget::drawTitleSafeArea() {
|
||||
}
|
||||
|
||||
glLoadIdentity();
|
||||
glOrtho(-halfWidth, halfWidth, halfHeight, -halfHeight, -1, 1);
|
||||
glOrtho(-halfWidth, halfWidth, halfHeight, -halfHeight, 0, 1);
|
||||
|
||||
glColor4f(0.66f, 0.66f, 0.66f, 1.0f);
|
||||
glBegin(GL_LINES);
|
||||
@@ -221,16 +305,17 @@ void ViewerWidget::drawTitleSafeArea() {
|
||||
}
|
||||
|
||||
GLuint ViewerWidget::draw_clip(QOpenGLFramebufferObject* fbo, GLuint texture, bool clear) {
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0, 1, 0, 1, -1, 1);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0, 1, 0, 1, -1, 1);
|
||||
|
||||
fbo->bind();
|
||||
fbo->bind();
|
||||
|
||||
if (clear) glClear(GL_COLOR_BUFFER_BIT);
|
||||
GL_DEFAULT_BLEND
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBegin(GL_QUADS);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0, 0); // top left
|
||||
glVertex2f(0, 0); // top left
|
||||
glTexCoord2f(1, 0); // top right
|
||||
@@ -263,7 +348,9 @@ void ViewerWidget::process_effect(Clip* c, Effect* e, double timecode, GLTexture
|
||||
}
|
||||
if (e->enable_superimpose) {
|
||||
GLuint superimpose_texture = e->process_superimpose(timecode);
|
||||
if (superimpose_texture != 0) composite_texture = draw_clip(c->fbo[!fbo_switcher], superimpose_texture, false);
|
||||
if (superimpose_texture != 0) {
|
||||
composite_texture = draw_clip(c->fbo[!fbo_switcher], superimpose_texture, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,10 +445,10 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(-half_width, half_width, half_height, -half_height, -1, 1);
|
||||
glOrtho(-half_width, half_width, half_height, -half_height, -1, 10);
|
||||
|
||||
for (int i=0;i<current_clips.size();i++) {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
GL_DEFAULT_BLEND
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
Clip* c = current_clips.at(i);
|
||||
@@ -434,17 +521,21 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
composite_texture = draw_clip(c->fbo[fbo_switcher], textureID, true);
|
||||
}
|
||||
|
||||
fbo_switcher = !fbo_switcher;
|
||||
fbo_switcher = !fbo_switcher;
|
||||
|
||||
// set up default coords
|
||||
GLTextureCoords coords;
|
||||
coords.grid_size = 1;
|
||||
coords.vertexTopLeftX = coords.vertexBottomLeftX = -video_width/2;
|
||||
coords.vertexTopLeftY = coords.vertexTopRightY = -video_height/2;
|
||||
coords.vertexTopRightX = coords.vertexBottomRightX = video_width/2;
|
||||
coords.vertexBottomLeftY = coords.vertexBottomRightY = video_height/2;
|
||||
coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0;
|
||||
coords.vertexBottomLeftY = coords.vertexBottomRightY = video_height/2;
|
||||
coords.vertexBottomLeftZ = coords.vertexBottomRightZ = coords.vertexTopLeftZ = coords.vertexTopRightZ = 1;
|
||||
coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0.0;
|
||||
coords.textureBottomLeftY = coords.textureBottomRightY = coords.textureTopRightX = coords.textureBottomRightX = 1.0;
|
||||
coords.textureTopLeftQ = coords.textureTopRightQ = coords.textureTopLeftQ = coords.textureBottomLeftQ = 1;
|
||||
|
||||
// set up autoscale
|
||||
if (c->autoscale && (video_width != s->width && video_height != s->height)) {
|
||||
float width_multiplier = (float) s->width / (float) video_width;
|
||||
float height_multiplier = (float) s->height / (float) video_height;
|
||||
@@ -453,11 +544,29 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
}
|
||||
|
||||
// EFFECT CODE START
|
||||
double timecode = ((double)(playhead-c->get_timeline_in_with_transition()+c->get_clip_in_with_transition())/(double)c->sequence->frame_rate);
|
||||
double timecode = get_timecode(c, playhead);
|
||||
|
||||
Effect* first_gizmo_effect = NULL;
|
||||
Effect* selected_effect = NULL;
|
||||
|
||||
for (int j=0;j<c->effects.size();j++) {
|
||||
process_effect(c, c->effects.at(j), timecode, coords, composite_texture, fbo_switcher, TA_NO_TRANSITION);
|
||||
Effect* e = c->effects.at(j);
|
||||
process_effect(c, e, timecode, coords, composite_texture, fbo_switcher, TA_NO_TRANSITION);
|
||||
|
||||
if (e->are_gizmos_enabled()) {
|
||||
if (first_gizmo_effect == NULL) first_gizmo_effect = e;
|
||||
if (e->container->selected) selected_effect = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rendering) {
|
||||
if (selected_effect != NULL) {
|
||||
gizmos = selected_effect;
|
||||
} else if (panel_timeline->is_clip_selected(c, true)) {
|
||||
gizmos = first_gizmo_effect;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->get_opening_transition() != NULL) {
|
||||
int transition_progress = playhead - c->get_timeline_in_with_transition();
|
||||
if (transition_progress < c->get_opening_transition()->get_length()) {
|
||||
@@ -496,43 +605,45 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
if (coords.grid_size <= 1) {
|
||||
glTexCoord2f(coords.textureTopLeftX, coords.textureTopLeftY); // top left
|
||||
glVertex2f(coords.vertexTopLeftX, coords.vertexTopLeftY); // top left
|
||||
glTexCoord2f(coords.textureTopRightX, coords.textureTopRightY); // top right
|
||||
glVertex2f(coords.vertexTopRightX, coords.vertexTopRightY); // top right
|
||||
glTexCoord2f(coords.textureBottomRightX, coords.textureBottomRightY); // bottom right
|
||||
glVertex2f(coords.vertexBottomRightX, coords.vertexBottomRightY); // bottom right
|
||||
glTexCoord2f(coords.textureBottomLeftX, coords.textureBottomLeftY); // bottom left
|
||||
glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left
|
||||
float z = 0.0f;
|
||||
|
||||
glTexCoord2f(coords.textureTopLeftX, coords.textureTopLeftY); // top left
|
||||
glVertex3f(coords.vertexTopLeftX, coords.vertexTopLeftY, z); // top left
|
||||
glTexCoord2f(coords.textureTopRightX, coords.textureTopRightY); // top right
|
||||
glVertex3f(coords.vertexTopRightX, coords.vertexTopRightY, z); // top right
|
||||
glTexCoord2f(coords.textureBottomRightX, coords.textureBottomRightY); // bottom right
|
||||
glVertex3f(coords.vertexBottomRightX, coords.vertexBottomRightY, z); // bottom right
|
||||
glTexCoord2f(coords.textureBottomLeftX, coords.textureBottomLeftY); // bottom left
|
||||
glVertex3f(coords.vertexBottomLeftX, coords.vertexBottomLeftY, z); // bottom left
|
||||
} else {
|
||||
double rows = coords.grid_size;
|
||||
double cols = coords.grid_size;
|
||||
float rows = coords.grid_size;
|
||||
float cols = coords.grid_size;
|
||||
|
||||
for (double i=0;i<rows;i++) {
|
||||
double row_prog = i/rows;
|
||||
double next_row_prog = (i+1)/rows;
|
||||
for (double j=0;j<cols;j++) {
|
||||
double col_prog = j/cols;
|
||||
double next_col_prog = (j+1)/cols;
|
||||
for (float k=0;k<rows;k++) {
|
||||
float row_prog = k/rows;
|
||||
float next_row_prog = (k+1)/rows;
|
||||
for (float j=0;j<cols;j++) {
|
||||
float col_prog = j/cols;
|
||||
float next_col_prog = (j+1)/cols;
|
||||
|
||||
double vertexTLX = double_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, row_prog);
|
||||
double vertexTRX = double_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, row_prog);
|
||||
double vertexBLX = double_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, next_row_prog);
|
||||
double vertexBRX = double_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, next_row_prog);
|
||||
float vertexTLX = float_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, row_prog);
|
||||
float vertexTRX = float_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, row_prog);
|
||||
float vertexBLX = float_lerp(coords.vertexTopLeftX, coords.vertexBottomLeftX, next_row_prog);
|
||||
float vertexBRX = float_lerp(coords.vertexTopRightX, coords.vertexBottomRightX, next_row_prog);
|
||||
|
||||
double vertexTLY = double_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, col_prog);
|
||||
double vertexTRY = double_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, next_col_prog);
|
||||
double vertexBLY = double_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, col_prog);
|
||||
double vertexBRY = double_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, next_col_prog);
|
||||
float vertexTLY = float_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, col_prog);
|
||||
float vertexTRY = float_lerp(coords.vertexTopLeftY, coords.vertexTopRightY, next_col_prog);
|
||||
float vertexBLY = float_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, col_prog);
|
||||
float vertexBRY = float_lerp(coords.vertexBottomLeftY, coords.vertexBottomRightY, next_col_prog);
|
||||
|
||||
glTexCoord2f(double_lerp(coords.textureTopLeftX, coords.textureTopRightX, col_prog), double_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, row_prog)); // top left
|
||||
glVertex2f(double_lerp(vertexTLX, vertexTRX, col_prog), double_lerp(vertexTLY, vertexBLY, row_prog)); // top left
|
||||
glTexCoord2f(double_lerp(coords.textureTopLeftX, coords.textureTopRightX, next_col_prog), double_lerp(coords.textureTopRightY, coords.textureBottomRightY, row_prog)); // top right
|
||||
glVertex2f(double_lerp(vertexTLX, vertexTRX, next_col_prog), double_lerp(vertexTRY, vertexBRY, row_prog)); // top right
|
||||
glTexCoord2f(double_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, next_col_prog), double_lerp(coords.textureTopRightY, coords.textureBottomRightY, next_row_prog)); // bottom right
|
||||
glVertex2f(double_lerp(vertexBLX, vertexBRX, next_col_prog), double_lerp(vertexTRY, vertexBRY, next_row_prog)); // bottom right
|
||||
glTexCoord2f(double_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, col_prog), double_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, next_row_prog)); // bottom left
|
||||
glVertex2f(double_lerp(vertexBLX, vertexBRX, col_prog), double_lerp(vertexTLY, vertexBLY, next_row_prog)); // bottom left
|
||||
glTexCoord2f(float_lerp(coords.textureTopLeftX, coords.textureTopRightX, col_prog), float_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, row_prog)); // top left
|
||||
glVertex2f(float_lerp(vertexTLX, vertexTRX, col_prog), float_lerp(vertexTLY, vertexBLY, row_prog)); // top left
|
||||
glTexCoord2f(float_lerp(coords.textureTopLeftX, coords.textureTopRightX, next_col_prog), float_lerp(coords.textureTopRightY, coords.textureBottomRightY, row_prog)); // top right
|
||||
glVertex2f(float_lerp(vertexTLX, vertexTRX, next_col_prog), float_lerp(vertexTRY, vertexBRY, row_prog)); // top right
|
||||
glTexCoord2f(float_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, next_col_prog), float_lerp(coords.textureTopRightY, coords.textureBottomRightY, next_row_prog)); // bottom right
|
||||
glVertex2f(float_lerp(vertexBLX, vertexBRX, next_col_prog), float_lerp(vertexTRY, vertexBRY, next_row_prog)); // bottom right
|
||||
glTexCoord2f(float_lerp(coords.textureBottomLeftX, coords.textureBottomRightX, col_prog), float_lerp(coords.textureTopLeftY, coords.textureBottomLeftY, next_row_prog)); // bottom left
|
||||
glVertex2f(float_lerp(vertexBLX, vertexBRX, col_prog), float_lerp(vertexTLY, vertexBLY, next_row_prog)); // bottom left
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,6 +652,13 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // unbind texture
|
||||
|
||||
if (gizmos != NULL && !drawn_gizmos) {
|
||||
gizmos->gizmo_draw(timecode, coords); // set correct gizmo coords
|
||||
gizmos->gizmo_world_to_screen();
|
||||
|
||||
drawn_gizmos = true;
|
||||
}
|
||||
|
||||
if (!nests.isEmpty()) {
|
||||
nests.last()->fbo[0]->release();
|
||||
if (default_fbo != NULL) default_fbo->bind();
|
||||
@@ -607,7 +725,10 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
||||
}
|
||||
|
||||
void ViewerWidget::paintGL() {
|
||||
drawn_gizmos = false;
|
||||
if (viewer->seq != NULL) {
|
||||
gizmos = NULL;
|
||||
|
||||
bool render_audio = (viewer->playing || rendering);
|
||||
bool loop = false;
|
||||
do {
|
||||
@@ -617,6 +738,7 @@ void ViewerWidget::paintGL() {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_DEPTH);
|
||||
|
||||
texture_failed = false;
|
||||
|
||||
@@ -665,6 +787,48 @@ void ViewerWidget::paintGL() {
|
||||
drawTitleSafeArea();
|
||||
}
|
||||
|
||||
if (gizmos != NULL && drawn_gizmos) {
|
||||
float color[4];
|
||||
glGetFloatv(GL_CURRENT_COLOR, color);
|
||||
|
||||
float dot_size = GIZMO_DOT_SIZE / width() * viewer->seq->width;
|
||||
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0, viewer->seq->width, viewer->seq->height, 0, -1, 10);
|
||||
float gizmo_z = 0.0f;
|
||||
for (int j=0;j<gizmos->gizmo_count();j++) {
|
||||
EffectGizmo* g = gizmos->gizmo(j);
|
||||
glColor4f(g->color.redF(), g->color.greenF(), g->color.blueF(), 1.0);
|
||||
switch (g->get_type()) {
|
||||
case GIZMO_TYPE_DOT: // draw dot
|
||||
glBegin(GL_QUADS);
|
||||
glVertex3f(g->screen_pos[0].x()-dot_size, g->screen_pos[0].y()-dot_size, gizmo_z);
|
||||
glVertex3f(g->screen_pos[0].x()+dot_size, g->screen_pos[0].y()-dot_size, gizmo_z);
|
||||
glVertex3f(g->screen_pos[0].x()+dot_size, g->screen_pos[0].y()+dot_size, gizmo_z);
|
||||
glVertex3f(g->screen_pos[0].x()-dot_size, g->screen_pos[0].y()+dot_size, gizmo_z);
|
||||
glEnd();
|
||||
break;
|
||||
case GIZMO_TYPE_POLY: // draw lines
|
||||
glBegin(GL_LINES);
|
||||
for (int k=1;k<g->get_point_count();k++) {
|
||||
glVertex3f(g->screen_pos[k-1].x(), g->screen_pos[k-1].y(), gizmo_z);
|
||||
glVertex3f(g->screen_pos[k].x(), g->screen_pos[k].y(), gizmo_z);
|
||||
}
|
||||
glVertex3f(g->screen_pos[g->get_point_count()-1].x(), g->screen_pos[g->get_point_count()-1].y(), gizmo_z);
|
||||
glVertex3f(g->screen_pos[0].x(), g->screen_pos[0].y(), gizmo_z);
|
||||
glEnd();
|
||||
break;
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
glColor4f(color[0], color[1], color[2], color[3]);
|
||||
|
||||
drawn_gizmos = true;
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH);
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
} while (loop);
|
||||
|
||||
+12
-2
@@ -1,4 +1,4 @@
|
||||
#ifndef VIEWERWIDGET_H
|
||||
#ifndef VIEWERWIDGET_H
|
||||
#define VIEWERWIDGET_H
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
@@ -8,15 +8,17 @@
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
class Viewer;
|
||||
struct Clip;
|
||||
struct MediaStream;
|
||||
class QOpenGLFramebufferObject;
|
||||
class Effect;
|
||||
class EffectGizmo;
|
||||
struct GLTextureCoords;
|
||||
|
||||
class ViewerWidget : public QOpenGLWidget
|
||||
class ViewerWidget : public QOpenGLWidget, QOpenGLFunctions
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -47,6 +49,14 @@ private:
|
||||
GLuint compose_sequence(QVector<Clip *> &nests, bool render_audio);
|
||||
GLuint draw_clip(QOpenGLFramebufferObject *clip, GLuint texture, bool clear);
|
||||
void process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher, int data);
|
||||
Effect* gizmos;
|
||||
int drag_start_x;
|
||||
int drag_start_y;
|
||||
int gizmo_x_mvmt;
|
||||
int gizmo_y_mvmt;
|
||||
EffectGizmo* selected_gizmo;
|
||||
EffectGizmo* get_gizmo_from_mouse(int x, int y);
|
||||
bool drawn_gizmos;
|
||||
private slots:
|
||||
void retry();
|
||||
void show_context_menu();
|
||||
|
||||
Reference in New Issue
Block a user