Merge branch 'master' into new_timecode

This commit is contained in:
itsmattkc
2018-12-01 12:24:32 +11:00
committed by GitHub
53 changed files with 1874 additions and 954 deletions
+2 -2
View File
@@ -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 -9
View File
@@ -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) {
+38 -28
View File
@@ -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);
}
}
+7
View File
@@ -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) {
+4 -2
View File
@@ -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;
}
+4 -7
View File
@@ -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) {
+3 -10
View File
@@ -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) {
+6 -15
View File
@@ -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:
{
+19 -50
View File
@@ -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)));
+5 -13
View File
@@ -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) {
+103 -36
View File
@@ -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);
}
}
+25 -11
View File
@@ -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
+3 -6
View File
@@ -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) {
+17
View File
@@ -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();
}
+13
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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);
}
+1
View File
@@ -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
View File
@@ -37,7 +37,7 @@ struct MediaStream {
// preview thumbnail/waveform
bool preview_done;
QPixmap video_preview;
QImage video_preview;
QVector<char> audio_preview;
};
+3 -4
View File
@@ -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
View File
@@ -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);
}
+2
View File
@@ -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
View File
@@ -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/>
+6 -2
View File
@@ -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
View File
@@ -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*) {
+8 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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') +
+2 -2
View File
@@ -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
View File
@@ -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++) {
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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:
{
+1 -1
View File
@@ -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;
+28
View File
@@ -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;
}
+34
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+8 -3
View File
@@ -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
View File
@@ -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
+8
View 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
View File
@@ -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
View File
@@ -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
+193
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();