Merge pull request #245 from olive-editor/bezierkeys
bezier keyframes and keyframe system overhaul
This commit is contained in:
+44
-44
@@ -57,7 +57,7 @@ enum ExportFormats {
|
|||||||
ExportDialog::ExportDialog(QWidget *parent) :
|
ExportDialog::ExportDialog(QWidget *parent) :
|
||||||
QDialog(parent)
|
QDialog(parent)
|
||||||
{
|
{
|
||||||
setWindowTitle("Export \"" + sequence->name + "\"");
|
setWindowTitle("Export \"" + sequence->name + "\"");
|
||||||
setup_ui();
|
setup_ui();
|
||||||
|
|
||||||
rangeCombobox->setCurrentIndex(0);
|
rangeCombobox->setCurrentIndex(0);
|
||||||
@@ -479,7 +479,7 @@ void ExportDialog::export_action() {
|
|||||||
connect(et, SIGNAL(finished()), this, SLOT(render_thread_finished()));
|
connect(et, SIGNAL(finished()), this, SLOT(render_thread_finished()));
|
||||||
connect(et, SIGNAL(progress_changed(int, qint64)), this, SLOT(update_progress_bar(int, qint64)));
|
connect(et, SIGNAL(progress_changed(int, qint64)), this, SLOT(update_progress_bar(int, qint64)));
|
||||||
|
|
||||||
closeActiveClips(sequence, true);
|
closeActiveClips(sequence);
|
||||||
|
|
||||||
mainWindow->autorecover_interval();
|
mainWindow->autorecover_interval();
|
||||||
|
|
||||||
@@ -603,40 +603,40 @@ void ExportDialog::setup_ui() {
|
|||||||
videoGroupbox->setFlat(false);
|
videoGroupbox->setFlat(false);
|
||||||
videoGroupbox->setCheckable(true);
|
videoGroupbox->setCheckable(true);
|
||||||
|
|
||||||
QGridLayout* videoGridLayout = new QGridLayout(videoGroupbox);
|
QGridLayout* videoGridLayout = new QGridLayout(videoGroupbox);
|
||||||
|
|
||||||
videoGridLayout->addWidget(new QLabel("Codec:"), 0, 0, 1, 1);
|
videoGridLayout->addWidget(new QLabel("Codec:"), 0, 0, 1, 1);
|
||||||
vcodecCombobox = new QComboBox(videoGroupbox);
|
vcodecCombobox = new QComboBox(videoGroupbox);
|
||||||
videoGridLayout->addWidget(vcodecCombobox, 0, 1, 1, 1);
|
videoGridLayout->addWidget(vcodecCombobox, 0, 1, 1, 1);
|
||||||
|
|
||||||
videoGridLayout->addWidget(new QLabel("Width:"), 1, 0, 1, 1);
|
videoGridLayout->addWidget(new QLabel("Width:"), 1, 0, 1, 1);
|
||||||
widthSpinbox = new QSpinBox(videoGroupbox);
|
widthSpinbox = new QSpinBox(videoGroupbox);
|
||||||
widthSpinbox->setMaximum(16777216);
|
widthSpinbox->setMaximum(16777216);
|
||||||
videoGridLayout->addWidget(widthSpinbox, 1, 1, 1, 1);
|
videoGridLayout->addWidget(widthSpinbox, 1, 1, 1, 1);
|
||||||
|
|
||||||
videoGridLayout->addWidget(new QLabel("Height:"), 2, 0, 1, 1);
|
videoGridLayout->addWidget(new QLabel("Height:"), 2, 0, 1, 1);
|
||||||
heightSpinbox = new QSpinBox(videoGroupbox);
|
heightSpinbox = new QSpinBox(videoGroupbox);
|
||||||
heightSpinbox->setMaximum(16777216);
|
heightSpinbox->setMaximum(16777216);
|
||||||
videoGridLayout->addWidget(heightSpinbox, 2, 1, 1, 1);
|
videoGridLayout->addWidget(heightSpinbox, 2, 1, 1, 1);
|
||||||
|
|
||||||
videoGridLayout->addWidget(new QLabel("Frame Rate:"), 3, 0, 1, 1);
|
videoGridLayout->addWidget(new QLabel("Frame Rate:"), 3, 0, 1, 1);
|
||||||
framerateSpinbox = new QDoubleSpinBox(videoGroupbox);
|
framerateSpinbox = new QDoubleSpinBox(videoGroupbox);
|
||||||
framerateSpinbox->setMaximum(60);
|
framerateSpinbox->setMaximum(60);
|
||||||
framerateSpinbox->setValue(0);
|
framerateSpinbox->setValue(0);
|
||||||
videoGridLayout->addWidget(framerateSpinbox, 3, 1, 1, 1);
|
videoGridLayout->addWidget(framerateSpinbox, 3, 1, 1, 1);
|
||||||
|
|
||||||
videoGridLayout->addWidget(new QLabel("Compression Type:"), 4, 0, 1, 1);
|
videoGridLayout->addWidget(new QLabel("Compression Type:"), 4, 0, 1, 1);
|
||||||
compressionTypeCombobox = new QComboBox(videoGroupbox);
|
compressionTypeCombobox = new QComboBox(videoGroupbox);
|
||||||
compressionTypeCombobox->addItem("Quality-based (Constant Rate Factor)");
|
compressionTypeCombobox->addItem("Quality-based (Constant Rate Factor)");
|
||||||
compressionTypeCombobox->addItem("File size-based (Two-Pass)");
|
compressionTypeCombobox->addItem("File size-based (Two-Pass)");
|
||||||
videoGridLayout->addWidget(compressionTypeCombobox, 4, 1, 1, 1);
|
videoGridLayout->addWidget(compressionTypeCombobox, 4, 1, 1, 1);
|
||||||
|
|
||||||
videoBitrateLabel = new QLabel(videoGroupbox);
|
videoBitrateLabel = new QLabel(videoGroupbox);
|
||||||
videoGridLayout->addWidget(videoBitrateLabel, 5, 0, 1, 1);
|
videoGridLayout->addWidget(videoBitrateLabel, 5, 0, 1, 1);
|
||||||
videobitrateSpinbox = new QDoubleSpinBox(videoGroupbox);
|
videobitrateSpinbox = new QDoubleSpinBox(videoGroupbox);
|
||||||
videobitrateSpinbox->setMaximum(100);
|
videobitrateSpinbox->setMaximum(100);
|
||||||
videobitrateSpinbox->setValue(2);
|
videobitrateSpinbox->setValue(2);
|
||||||
videoGridLayout->addWidget(videobitrateSpinbox, 5, 1, 1, 1);
|
videoGridLayout->addWidget(videobitrateSpinbox, 5, 1, 1, 1);
|
||||||
|
|
||||||
verticalLayout->addWidget(videoGroupbox);
|
verticalLayout->addWidget(videoGroupbox);
|
||||||
|
|
||||||
@@ -644,60 +644,60 @@ void ExportDialog::setup_ui() {
|
|||||||
audioGroupbox->setTitle("Audio");
|
audioGroupbox->setTitle("Audio");
|
||||||
audioGroupbox->setCheckable(true);
|
audioGroupbox->setCheckable(true);
|
||||||
|
|
||||||
QGridLayout* audioGridLayout = new QGridLayout(audioGroupbox);
|
QGridLayout* audioGridLayout = new QGridLayout(audioGroupbox);
|
||||||
|
|
||||||
audioGridLayout->addWidget(new QLabel("Codec:"), 0, 0, 1, 1);
|
audioGridLayout->addWidget(new QLabel("Codec:"), 0, 0, 1, 1);
|
||||||
acodecCombobox = new QComboBox(audioGroupbox);
|
acodecCombobox = new QComboBox(audioGroupbox);
|
||||||
audioGridLayout->addWidget(acodecCombobox, 0, 1, 1, 1);
|
audioGridLayout->addWidget(acodecCombobox, 0, 1, 1, 1);
|
||||||
|
|
||||||
audioGridLayout->addWidget(new QLabel("Sampling Rate:"), 1, 0, 1, 1);
|
audioGridLayout->addWidget(new QLabel("Sampling Rate:"), 1, 0, 1, 1);
|
||||||
samplingRateSpinbox = new QSpinBox(audioGroupbox);
|
samplingRateSpinbox = new QSpinBox(audioGroupbox);
|
||||||
samplingRateSpinbox->setMaximum(96000);
|
samplingRateSpinbox->setMaximum(96000);
|
||||||
samplingRateSpinbox->setValue(0);
|
samplingRateSpinbox->setValue(0);
|
||||||
audioGridLayout->addWidget(samplingRateSpinbox, 1, 1, 1, 1);
|
audioGridLayout->addWidget(samplingRateSpinbox, 1, 1, 1, 1);
|
||||||
|
|
||||||
audioGridLayout->addWidget(new QLabel("Bitrate (Kbps/CBR):"), 3, 0, 1, 1);
|
audioGridLayout->addWidget(new QLabel("Bitrate (Kbps/CBR):"), 3, 0, 1, 1);
|
||||||
audiobitrateSpinbox = new QSpinBox(audioGroupbox);
|
audiobitrateSpinbox = new QSpinBox(audioGroupbox);
|
||||||
audiobitrateSpinbox->setMaximum(320);
|
audiobitrateSpinbox->setMaximum(320);
|
||||||
audiobitrateSpinbox->setValue(256);
|
audiobitrateSpinbox->setValue(256);
|
||||||
audioGridLayout->addWidget(audiobitrateSpinbox, 3, 1, 1, 1);
|
audioGridLayout->addWidget(audiobitrateSpinbox, 3, 1, 1, 1);
|
||||||
|
|
||||||
verticalLayout->addWidget(audioGroupbox);
|
verticalLayout->addWidget(audioGroupbox);
|
||||||
|
|
||||||
QHBoxLayout* progressLayout = new QHBoxLayout();
|
QHBoxLayout* progressLayout = new QHBoxLayout();
|
||||||
progressBar = new QProgressBar(this);
|
progressBar = new QProgressBar(this);
|
||||||
progressBar->setFormat("%p% (ETA: 0:00:00)");
|
progressBar->setFormat("%p% (ETA: 0:00:00)");
|
||||||
progressBar->setEnabled(false);
|
progressBar->setEnabled(false);
|
||||||
progressBar->setValue(0);
|
progressBar->setValue(0);
|
||||||
progressLayout->addWidget(progressBar);
|
progressLayout->addWidget(progressBar);
|
||||||
|
|
||||||
renderCancel = new QPushButton(this);
|
renderCancel = new QPushButton(this);
|
||||||
renderCancel->setText("x");
|
renderCancel->setText("x");
|
||||||
renderCancel->setEnabled(false);
|
renderCancel->setEnabled(false);
|
||||||
renderCancel->setMaximumSize(QSize(20, 16777215));
|
renderCancel->setMaximumSize(QSize(20, 16777215));
|
||||||
connect(renderCancel, SIGNAL(clicked(bool)), this, SLOT(cancel_render()));
|
connect(renderCancel, SIGNAL(clicked(bool)), this, SLOT(cancel_render()));
|
||||||
progressLayout->addWidget(renderCancel);
|
progressLayout->addWidget(renderCancel);
|
||||||
|
|
||||||
verticalLayout->addLayout(progressLayout);
|
verticalLayout->addLayout(progressLayout);
|
||||||
|
|
||||||
QHBoxLayout* buttonLayout = new QHBoxLayout();
|
QHBoxLayout* buttonLayout = new QHBoxLayout();
|
||||||
buttonLayout->addStretch();
|
buttonLayout->addStretch();
|
||||||
|
|
||||||
export_button = new QPushButton(this);
|
export_button = new QPushButton(this);
|
||||||
export_button->setText("Export");
|
export_button->setText("Export");
|
||||||
connect(export_button, SIGNAL(clicked(bool)), this, SLOT(export_action()));
|
connect(export_button, SIGNAL(clicked(bool)), this, SLOT(export_action()));
|
||||||
|
|
||||||
buttonLayout->addWidget(export_button);
|
buttonLayout->addWidget(export_button);
|
||||||
|
|
||||||
cancel_button = new QPushButton(this);
|
cancel_button = new QPushButton(this);
|
||||||
cancel_button->setText("Cancel");
|
cancel_button->setText("Cancel");
|
||||||
connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject()));
|
connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(reject()));
|
||||||
|
|
||||||
buttonLayout->addWidget(cancel_button);
|
buttonLayout->addWidget(cancel_button);
|
||||||
|
|
||||||
buttonLayout->addStretch();
|
buttonLayout->addStretch();
|
||||||
|
|
||||||
verticalLayout->addLayout(buttonLayout);
|
verticalLayout->addLayout(buttonLayout);
|
||||||
|
|
||||||
connect(formatCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(format_changed(int)));
|
connect(formatCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(format_changed(int)));
|
||||||
connect(compressionTypeCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(comp_type_changed(int)));
|
connect(compressionTypeCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(comp_type_changed(int)));
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ void SpeedDialog::accept() {
|
|||||||
|
|
||||||
for (int i=0;i<clips.size();i++) {
|
for (int i=0;i<clips.size();i++) {
|
||||||
Clip* c = clips.at(i);
|
Clip* c = clips.at(i);
|
||||||
if (c->open) close_clip(c);
|
if (c->open) close_clip(c, true);
|
||||||
|
|
||||||
if (c->track >= 0
|
if (c->track >= 0
|
||||||
&& maintain_pitch->checkState() != Qt::PartiallyChecked
|
&& maintain_pitch->checkState() != Qt::PartiallyChecked
|
||||||
|
|||||||
@@ -4,15 +4,15 @@
|
|||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||||
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE, "amount");
|
amount_val = add_row("Amount")->add_field(EFFECT_FIELD_DOUBLE, "amount");
|
||||||
amount_val->set_double_minimum_value(0);
|
amount_val->set_double_minimum_value(0);
|
||||||
amount_val->set_double_maximum_value(100);
|
amount_val->set_double_maximum_value(100);
|
||||||
amount_val->set_double_default_value(20);
|
amount_val->set_double_default_value(20);
|
||||||
|
|
||||||
mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL, "mix");
|
mix_val = add_row("Mix")->add_field(EFFECT_FIELD_BOOL, "mix");
|
||||||
mix_val->set_bool_value(true);
|
mix_val->set_bool_value(true);
|
||||||
|
|
||||||
srand(QDateTime::currentMSecsSinceEpoch());
|
srand(QDateTime::currentMSecsSinceEpoch());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
|
void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
|
||||||
|
|||||||
@@ -5,59 +5,59 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
CornerPinEffect::CornerPinEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
|
CornerPinEffect::CornerPinEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
|
||||||
enable_coords = true;
|
enable_coords = true;
|
||||||
enable_shader = true;
|
enable_shader = true;
|
||||||
|
|
||||||
EffectRow* top_left = add_row("Top Left:");
|
EffectRow* top_left = add_row("Top Left");
|
||||||
top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx");
|
top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx");
|
||||||
top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty");
|
top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty");
|
||||||
|
|
||||||
EffectRow* top_right = add_row("Top Right:");
|
EffectRow* top_right = add_row("Top Right");
|
||||||
top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx");
|
top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx");
|
||||||
top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty");
|
top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty");
|
||||||
|
|
||||||
EffectRow* bottom_left = add_row("Bottom Left:");
|
EffectRow* bottom_left = add_row("Bottom Left");
|
||||||
bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx");
|
bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx");
|
||||||
bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty");
|
bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty");
|
||||||
|
|
||||||
EffectRow* bottom_right = add_row("Bottom Right:");
|
EffectRow* bottom_right = add_row("Bottom Right");
|
||||||
bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx");
|
bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx");
|
||||||
bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty");
|
bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty");
|
||||||
|
|
||||||
perspective = add_row("Perspective:")->add_field(EFFECT_FIELD_BOOL, "perspective");
|
perspective = add_row("Perspective")->add_field(EFFECT_FIELD_BOOL, "perspective");
|
||||||
perspective->set_bool_value(true);
|
perspective->set_bool_value(true);
|
||||||
|
|
||||||
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
top_left_gizmo->x_field1 = top_left_x;
|
top_left_gizmo->x_field1 = top_left_x;
|
||||||
top_left_gizmo->y_field1 = top_left_y;
|
top_left_gizmo->y_field1 = top_left_y;
|
||||||
|
|
||||||
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
top_right_gizmo->x_field1 = top_right_x;
|
top_right_gizmo->x_field1 = top_right_x;
|
||||||
top_right_gizmo->y_field1 = top_right_y;
|
top_right_gizmo->y_field1 = top_right_y;
|
||||||
|
|
||||||
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
bottom_left_gizmo->x_field1 = bottom_left_x;
|
bottom_left_gizmo->x_field1 = bottom_left_x;
|
||||||
bottom_left_gizmo->y_field1 = bottom_left_y;
|
bottom_left_gizmo->y_field1 = bottom_left_y;
|
||||||
|
|
||||||
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
bottom_right_gizmo->x_field1 = bottom_right_x;
|
bottom_right_gizmo->x_field1 = bottom_right_x;
|
||||||
bottom_right_gizmo->y_field1 = bottom_right_y;
|
bottom_right_gizmo->y_field1 = bottom_right_y;
|
||||||
|
|
||||||
vertPath = "cornerpin.vert";
|
vertPath = "cornerpin.vert";
|
||||||
fragPath = "cornerpin.frag";
|
fragPath = "cornerpin.frag";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int data) {
|
void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int data) {
|
||||||
coords.vertexTopLeftX += top_left_x->get_double_value(timecode);
|
coords.vertexTopLeftX += top_left_x->get_double_value(timecode);
|
||||||
coords.vertexTopLeftY += top_left_y->get_double_value(timecode);
|
coords.vertexTopLeftY += top_left_y->get_double_value(timecode);
|
||||||
|
|
||||||
coords.vertexTopRightX += top_right_x->get_double_value(timecode);
|
coords.vertexTopRightX += top_right_x->get_double_value(timecode);
|
||||||
coords.vertexTopRightY += top_right_y->get_double_value(timecode);
|
coords.vertexTopRightY += top_right_y->get_double_value(timecode);
|
||||||
|
|
||||||
coords.vertexBottomLeftX += bottom_left_x->get_double_value(timecode);
|
coords.vertexBottomLeftX += bottom_left_x->get_double_value(timecode);
|
||||||
coords.vertexBottomLeftY += bottom_left_y->get_double_value(timecode);
|
coords.vertexBottomLeftY += bottom_left_y->get_double_value(timecode);
|
||||||
|
|
||||||
coords.vertexBottomRightX += bottom_right_x->get_double_value(timecode);
|
coords.vertexBottomRightX += bottom_right_x->get_double_value(timecode);
|
||||||
coords.vertexBottomRightY += bottom_right_y->get_double_value(timecode);
|
coords.vertexBottomRightY += bottom_right_y->get_double_value(timecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +66,12 @@ void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords) {
|
|||||||
glslProgram->setUniformValue("p1", (GLfloat) coords.vertexBottomRightX, (GLfloat) coords.vertexBottomRightY);
|
glslProgram->setUniformValue("p1", (GLfloat) coords.vertexBottomRightX, (GLfloat) coords.vertexBottomRightY);
|
||||||
glslProgram->setUniformValue("p2", (GLfloat) coords.vertexTopLeftX, (GLfloat) coords.vertexTopLeftY);
|
glslProgram->setUniformValue("p2", (GLfloat) coords.vertexTopLeftX, (GLfloat) coords.vertexTopLeftY);
|
||||||
glslProgram->setUniformValue("p3", (GLfloat) coords.vertexTopRightX, (GLfloat) coords.vertexTopRightY);
|
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) {
|
void CornerPinEffect::gizmo_draw(double timecode, GLTextureCoords &coords) {
|
||||||
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
||||||
top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
||||||
bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
||||||
bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
#include "ui/collapsiblewidget.h"
|
#include "ui/collapsiblewidget.h"
|
||||||
|
|
||||||
PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||||
EffectRow* pan_row = add_row("Pan:");
|
EffectRow* pan_row = add_row("Pan");
|
||||||
pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE, "pan");
|
pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE, "pan");
|
||||||
pan_val->set_double_minimum_value(-100);
|
pan_val->set_double_minimum_value(-100);
|
||||||
pan_val->set_double_maximum_value(100);
|
pan_val->set_double_maximum_value(100);
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
pan_val->set_double_default_value(0);
|
pan_val->set_double_default_value(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
||||||
|
|||||||
@@ -16,19 +16,19 @@
|
|||||||
ShakeEffect::ShakeEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
|
ShakeEffect::ShakeEffect(Clip *c, const EffectMeta *em) : Effect(c, em) {
|
||||||
enable_coords = true;
|
enable_coords = true;
|
||||||
|
|
||||||
EffectRow* intensity_row = add_row("Intensity:");
|
EffectRow* intensity_row = add_row("Intensity");
|
||||||
intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE, "intensity");
|
intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE, "intensity");
|
||||||
intensity_val->set_double_minimum_value(0);
|
intensity_val->set_double_minimum_value(0);
|
||||||
|
|
||||||
EffectRow* rotation_row = add_row("Rotation:");
|
EffectRow* rotation_row = add_row("Rotation");
|
||||||
rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
|
rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
|
||||||
rotation_val->set_double_minimum_value(0);
|
rotation_val->set_double_minimum_value(0);
|
||||||
|
|
||||||
EffectRow* frequency_row = add_row("Frequency:");
|
EffectRow* frequency_row = add_row("Frequency");
|
||||||
frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE, "frequency");
|
frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE, "frequency");
|
||||||
frequency_val->set_double_minimum_value(0);
|
frequency_val->set_double_minimum_value(0);
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
intensity_val->set_double_default_value(25);
|
intensity_val->set_double_default_value(25);
|
||||||
rotation_val->set_double_default_value(10);
|
rotation_val->set_double_default_value(10);
|
||||||
frequency_val->set_double_default_value(5);
|
frequency_val->set_double_default_value(5);
|
||||||
|
|||||||
@@ -21,36 +21,36 @@
|
|||||||
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
||||||
enable_superimpose = true;
|
enable_superimpose = true;
|
||||||
|
|
||||||
solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO, "type");
|
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("Solid Color", SOLID_TYPE_COLOR);
|
||||||
solid_type->add_combo_item("SMPTE Bars", SOLID_TYPE_BARS);
|
solid_type->add_combo_item("SMPTE Bars", SOLID_TYPE_BARS);
|
||||||
solid_type->add_combo_item("Checkerboard", SOLID_TYPE_CHECKERBOARD);
|
solid_type->add_combo_item("Checkerboard", SOLID_TYPE_CHECKERBOARD);
|
||||||
|
|
||||||
opacity_field = add_row("Opacity:")->add_field(EFFECT_FIELD_DOUBLE, "opacity");
|
opacity_field = add_row("Opacity")->add_field(EFFECT_FIELD_DOUBLE, "opacity");
|
||||||
opacity_field->set_double_minimum_value(0);
|
opacity_field->set_double_minimum_value(0);
|
||||||
opacity_field->set_double_maximum_value(100);
|
opacity_field->set_double_maximum_value(100);
|
||||||
opacity_field->set_double_default_value(100);
|
opacity_field->set_double_default_value(100);
|
||||||
|
|
||||||
solid_color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, "color");
|
solid_color_field = add_row("Color")->add_field(EFFECT_FIELD_COLOR, "color");
|
||||||
solid_color_field->set_color_value(Qt::red);
|
solid_color_field->set_color_value(Qt::red);
|
||||||
|
|
||||||
checkerboard_size_field = add_row("Checkerboard Size:")->add_field(EFFECT_FIELD_DOUBLE, "checker_size");
|
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_minimum_value(1);
|
||||||
checkerboard_size_field->set_double_default_value(10);
|
checkerboard_size_field->set_double_default_value(10);
|
||||||
|
|
||||||
// hacky but eh
|
// hacky but eh
|
||||||
QComboBox* solid_type_combo = static_cast<QComboBox*>(solid_type->get_ui_element());
|
QComboBox* solid_type_combo = static_cast<QComboBox*>(solid_type->get_ui_element());
|
||||||
connect(solid_type_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(ui_update(int)));
|
connect(solid_type_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(ui_update(int)));
|
||||||
ui_update(solid_type_combo->currentIndex());
|
ui_update(solid_type_combo->currentIndex());
|
||||||
|
|
||||||
/*vertPath = ":/shaders/common.vert";
|
/*vertPath = ":/shaders/common.vert";
|
||||||
fragPath = ":/shaders/solideffect.frag";*/
|
fragPath = ":/shaders/solideffect.frag";*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void SolidEffect::redraw(double timecode) {
|
void SolidEffect::redraw(double timecode) {
|
||||||
int w = img.width();
|
int w = img.width();
|
||||||
int h = img.height();
|
int h = img.height();
|
||||||
int alpha = qRound(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()) {
|
switch (solid_type->get_combo_data(timecode).toInt()) {
|
||||||
case SOLID_TYPE_COLOR:
|
case SOLID_TYPE_COLOR:
|
||||||
{
|
{
|
||||||
@@ -141,37 +141,37 @@ void SolidEffect::redraw(double timecode) {
|
|||||||
third_color.setAlpha(alpha);
|
third_color.setAlpha(alpha);
|
||||||
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
|
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SOLID_TYPE_CHECKERBOARD:
|
case SOLID_TYPE_CHECKERBOARD:
|
||||||
{
|
{
|
||||||
// draw checkboard
|
// draw checkboard
|
||||||
QPainter p(&img);
|
QPainter p(&img);
|
||||||
img.fill(Qt::transparent);
|
img.fill(Qt::transparent);
|
||||||
|
|
||||||
int checker_width = qCeil(checkerboard_size_field->get_double_value(timecode));
|
int checker_width = qCeil(checkerboard_size_field->get_double_value(timecode));
|
||||||
int checker_x, checker_y;
|
int checker_x, checker_y;
|
||||||
int checkerboard_size_w = qCeil(double(w)/checker_width);
|
int checkerboard_size_w = qCeil(double(w)/checker_width);
|
||||||
int checkerboard_size_h = qCeil(double(h)/checker_width);
|
int checkerboard_size_h = qCeil(double(h)/checker_width);
|
||||||
|
|
||||||
QColor checker_odd(QColor(0, 0, 0, alpha));
|
QColor checker_odd(QColor(0, 0, 0, alpha));
|
||||||
QColor checker_even(solid_color_field->get_color_value(timecode));
|
QColor checker_even(solid_color_field->get_color_value(timecode));
|
||||||
checker_even.setAlpha(alpha);
|
checker_even.setAlpha(alpha);
|
||||||
QVector<QColor> checker_color{checker_odd, checker_even};
|
QVector<QColor> checker_color{checker_odd, checker_even};
|
||||||
|
|
||||||
for(int i = 0; i < checkerboard_size_w; i++){
|
for(int i = 0; i < checkerboard_size_w; i++){
|
||||||
checker_x = checker_width*i;
|
checker_x = checker_width*i;
|
||||||
for(int j = 0; j < checkerboard_size_h; j++){
|
for(int j = 0; j < checkerboard_size_h; j++){
|
||||||
checker_y = checker_width*j;
|
checker_y = checker_width*j;
|
||||||
p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]);
|
p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SolidEffect::ui_update(int i) {
|
void SolidEffect::ui_update(int i) {
|
||||||
solid_color_field->set_enabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD);
|
solid_color_field->set_enabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD);
|
||||||
checkerboard_size_field->set_enabled(i == SOLID_TYPE_CHECKERBOARD);
|
checkerboard_size_field->set_enabled(i == SOLID_TYPE_CHECKERBOARD);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,43 +24,43 @@ TextEffect::TextEffect(Clip *c, const EffectMeta* em) :
|
|||||||
Effect(c, em)
|
Effect(c, em)
|
||||||
{
|
{
|
||||||
enable_superimpose = true;
|
enable_superimpose = true;
|
||||||
enable_shader = true;
|
enable_shader = true;
|
||||||
|
|
||||||
text_val = add_row("Text:")->add_field(EFFECT_FIELD_STRING, "text", 2);
|
text_val = add_row("Text")->add_field(EFFECT_FIELD_STRING, "text", 2);
|
||||||
|
|
||||||
set_font_combobox = add_row("Font:")->add_field(EFFECT_FIELD_FONT, "font", 2);
|
set_font_combobox = add_row("Font")->add_field(EFFECT_FIELD_FONT, "font", 2);
|
||||||
|
|
||||||
size_val = add_row("Size:")->add_field(EFFECT_FIELD_DOUBLE, "size", 2);
|
size_val = add_row("Size")->add_field(EFFECT_FIELD_DOUBLE, "size", 2);
|
||||||
size_val->set_double_minimum_value(0);
|
size_val->set_double_minimum_value(0);
|
||||||
|
|
||||||
set_color_button = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
set_color_button = add_row("Color")->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
||||||
|
|
||||||
EffectRow* alignment_row = add_row("Alignment:");
|
EffectRow* alignment_row = add_row("Alignment");
|
||||||
halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "halign");
|
halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "halign");
|
||||||
halign_field->add_combo_item("Left", Qt::AlignLeft);
|
halign_field->add_combo_item("Left", Qt::AlignLeft);
|
||||||
halign_field->add_combo_item("Center", Qt::AlignHCenter);
|
halign_field->add_combo_item("Center", Qt::AlignHCenter);
|
||||||
halign_field->add_combo_item("Right", Qt::AlignRight);
|
halign_field->add_combo_item("Right", Qt::AlignRight);
|
||||||
halign_field->add_combo_item("Justify", Qt::AlignJustify);
|
halign_field->add_combo_item("Justify", Qt::AlignJustify);
|
||||||
|
|
||||||
valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "valign");
|
valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "valign");
|
||||||
valign_field->add_combo_item("Top", Qt::AlignTop);
|
valign_field->add_combo_item("Top", Qt::AlignTop);
|
||||||
valign_field->add_combo_item("Center", Qt::AlignVCenter);
|
valign_field->add_combo_item("Center", Qt::AlignVCenter);
|
||||||
valign_field->add_combo_item("Bottom", Qt::AlignBottom);
|
valign_field->add_combo_item("Bottom", Qt::AlignBottom);
|
||||||
|
|
||||||
word_wrap_field = add_row("Word Wrap:")->add_field(EFFECT_FIELD_BOOL, "wordwrap", 2);
|
word_wrap_field = add_row("Word Wrap")->add_field(EFFECT_FIELD_BOOL, "wordwrap", 2);
|
||||||
|
|
||||||
outline_bool = add_row("Outline:")->add_field(EFFECT_FIELD_BOOL, "outline", 2);
|
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_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 = add_row("Outline Width")->add_field(EFFECT_FIELD_DOUBLE, "outlinewidth", 2);
|
||||||
outline_width->set_double_minimum_value(0);
|
outline_width->set_double_minimum_value(0);
|
||||||
|
|
||||||
shadow_bool = add_row("Shadow:")->add_field(EFFECT_FIELD_BOOL, "shadow", 2);
|
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_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 = add_row("Shadow Distance")->add_field(EFFECT_FIELD_DOUBLE, "shadowdistance", 2);
|
||||||
shadow_distance->set_double_minimum_value(0);
|
shadow_distance->set_double_minimum_value(0);
|
||||||
shadow_softness = add_row("Shadow Softness:")->add_field(EFFECT_FIELD_DOUBLE, "shadowsoftness", 2);
|
shadow_softness = add_row("Shadow Softness")->add_field(EFFECT_FIELD_DOUBLE, "shadowsoftness", 2);
|
||||||
shadow_softness->set_double_minimum_value(0);
|
shadow_softness->set_double_minimum_value(0);
|
||||||
shadow_opacity = add_row("Shadow Opacity:")->add_field(EFFECT_FIELD_DOUBLE, "shadowopacity", 2);
|
shadow_opacity = add_row("Shadow Opacity")->add_field(EFFECT_FIELD_DOUBLE, "shadowopacity", 2);
|
||||||
shadow_opacity->set_double_minimum_value(0);
|
shadow_opacity->set_double_minimum_value(0);
|
||||||
shadow_opacity->set_double_maximum_value(100);
|
shadow_opacity->set_double_maximum_value(100);
|
||||||
|
|
||||||
@@ -78,13 +78,13 @@ TextEffect::TextEffect(Clip *c, const EffectMeta* em) :
|
|||||||
outline_width->set_double_default_value(20);
|
outline_width->set_double_default_value(20);
|
||||||
|
|
||||||
outline_enable(false);
|
outline_enable(false);
|
||||||
shadow_enable(false);
|
shadow_enable(false);
|
||||||
|
|
||||||
connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool)));
|
connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool)));
|
||||||
connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool)));
|
connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool)));
|
||||||
|
|
||||||
vertPath = "common.vert";
|
vertPath = "common.vert";
|
||||||
fragPath = "dropshadow.frag";
|
fragPath = "dropshadow.frag";
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEffect::redraw(double timecode) {
|
void TextEffect::redraw(double timecode) {
|
||||||
@@ -170,7 +170,7 @@ void TextEffect::redraw(double timecode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path.addText(text_x, text_y, font, lines.at(i));
|
path.addText(text_x, text_y, font, lines.at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw outline
|
// draw outline
|
||||||
int outline_width_val = outline_width->get_double_value(timecode);
|
int outline_width_val = outline_width->get_double_value(timecode);
|
||||||
@@ -185,7 +185,7 @@ void TextEffect::redraw(double timecode) {
|
|||||||
// draw "master" text
|
// draw "master" text
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(set_color_button->get_color_value(timecode));
|
p.setBrush(set_color_button->get_color_value(timecode));
|
||||||
p.drawPath(path);
|
p.drawPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEffect::shadow_enable(bool e) {
|
void TextEffect::shadow_enable(bool e) {
|
||||||
|
|||||||
@@ -24,82 +24,82 @@
|
|||||||
#include "playback/playback.h"
|
#include "playback/playback.h"
|
||||||
|
|
||||||
TimecodeEffect::TimecodeEffect(Clip *c, const EffectMeta* em) :
|
TimecodeEffect::TimecodeEffect(Clip *c, const EffectMeta* em) :
|
||||||
Effect(c, em)
|
Effect(c, em)
|
||||||
{
|
{
|
||||||
enable_always_update = true;
|
enable_always_update = true;
|
||||||
enable_superimpose = true;
|
enable_superimpose = true;
|
||||||
|
|
||||||
EffectRow* tc_row = add_row("Timecode:");
|
EffectRow* tc_row = add_row("Timecode");
|
||||||
tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector");
|
tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector");
|
||||||
tc_select->add_combo_item("Sequence", true);
|
tc_select->add_combo_item("Sequence", true);
|
||||||
tc_select->add_combo_item("Media", false);
|
tc_select->add_combo_item("Media", false);
|
||||||
tc_select->set_combo_index(0);
|
tc_select->set_combo_index(0);
|
||||||
|
|
||||||
scale_val = add_row("Scale:")->add_field(EFFECT_FIELD_DOUBLE, "scale", 2);
|
scale_val = add_row("Scale")->add_field(EFFECT_FIELD_DOUBLE, "scale", 2);
|
||||||
scale_val->set_double_minimum_value(1);
|
scale_val->set_double_minimum_value(1);
|
||||||
scale_val->set_double_default_value(100);
|
scale_val->set_double_default_value(100);
|
||||||
scale_val->set_double_maximum_value(1000);
|
scale_val->set_double_maximum_value(1000);
|
||||||
|
|
||||||
color_val = add_row("Color:")->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
color_val = add_row("Color")->add_field(EFFECT_FIELD_COLOR, "color", 2);
|
||||||
color_val->set_color_value(Qt::white);
|
color_val->set_color_value(Qt::white);
|
||||||
|
|
||||||
color_bg_val = add_row("Background Color:")->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2);
|
color_bg_val = add_row("Background Color")->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2);
|
||||||
color_bg_val->set_color_value(Qt::black);
|
color_bg_val->set_color_value(Qt::black);
|
||||||
|
|
||||||
bg_alpha = add_row("Background Opacity:")->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2);
|
bg_alpha = add_row("Background Opacity")->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2);
|
||||||
bg_alpha->set_double_minimum_value(0);
|
bg_alpha->set_double_minimum_value(0);
|
||||||
bg_alpha->set_double_maximum_value(100);
|
bg_alpha->set_double_maximum_value(100);
|
||||||
bg_alpha->set_double_default_value(50);
|
bg_alpha->set_double_default_value(50);
|
||||||
|
|
||||||
EffectRow* offset = add_row("Offset:");
|
EffectRow* offset = add_row("Offset");
|
||||||
offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx");
|
offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx");
|
||||||
offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety");
|
offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety");
|
||||||
|
|
||||||
prepend_text = add_row("Prepend:")->add_field(EFFECT_FIELD_STRING, "prepend", 2);
|
prepend_text = add_row("Prepend")->add_field(EFFECT_FIELD_STRING, "prepend", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TimecodeEffect::redraw(double timecode) {
|
void TimecodeEffect::redraw(double timecode) {
|
||||||
if (tc_select->get_combo_data(timecode).toBool()){
|
if (tc_select->get_combo_data(timecode).toBool()){
|
||||||
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(sequence->playhead, config.timecode_view, sequence->frame_rate);}
|
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(sequence->playhead, config.timecode_view, sequence->frame_rate);}
|
||||||
else {
|
else {
|
||||||
double media_rate = parent_clip->getMediaFrameRate();
|
double media_rate = parent_clip->getMediaFrameRate();
|
||||||
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, config.timecode_view, media_rate);}
|
display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, config.timecode_view, media_rate);}
|
||||||
img.fill(Qt::transparent);
|
img.fill(Qt::transparent);
|
||||||
|
|
||||||
QPainter p(&img);
|
QPainter p(&img);
|
||||||
p.setRenderHint(QPainter::Antialiasing);
|
p.setRenderHint(QPainter::Antialiasing);
|
||||||
int width = img.width();
|
int width = img.width();
|
||||||
int height = img.height();
|
int height = img.height();
|
||||||
|
|
||||||
// set font
|
// set font
|
||||||
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
|
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
|
||||||
font.setFamily("Helvetica");
|
font.setFamily("Helvetica");
|
||||||
font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10)));
|
font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10)));
|
||||||
p.setFont(font);
|
p.setFont(font);
|
||||||
QFontMetrics fm(font);
|
QFontMetrics fm(font);
|
||||||
|
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
|
|
||||||
int text_x, text_y, rect_y, offset_x, offset_y;
|
int text_x, text_y, rect_y, offset_x, offset_y;
|
||||||
int text_height = fm.height();
|
int text_height = fm.height();
|
||||||
int text_width = fm.width(display_timecode);
|
int text_width = fm.width(display_timecode);
|
||||||
QColor background_color = color_bg_val->get_color_value(timecode);
|
QColor background_color = color_bg_val->get_color_value(timecode);
|
||||||
int alpha_val = bg_alpha->get_double_value(timecode)*2.55;
|
int alpha_val = bg_alpha->get_double_value(timecode)*2.55;
|
||||||
background_color.setAlpha(alpha_val);
|
background_color.setAlpha(alpha_val);
|
||||||
|
|
||||||
offset_x = int(offset_x_val->get_double_value(timecode));
|
offset_x = int(offset_x_val->get_double_value(timecode));
|
||||||
offset_y = int(offset_y_val->get_double_value(timecode));
|
offset_y = int(offset_y_val->get_double_value(timecode));
|
||||||
|
|
||||||
text_x = offset_x + (width/2) - (text_width/2);
|
text_x = offset_x + (width/2) - (text_width/2);
|
||||||
text_y = offset_y + height - height/10;
|
text_y = offset_y + height - height/10;
|
||||||
rect_y = text_y + fm.descent()/2 - text_height;
|
rect_y = text_y + fm.descent()/2 - text_height;
|
||||||
|
|
||||||
path.addText(text_x, text_y, font, display_timecode);
|
path.addText(text_x, text_y, font, display_timecode);
|
||||||
|
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(background_color);
|
p.setBrush(background_color);
|
||||||
p.drawRect(QRect(text_x-fm.descent()/2, rect_y, text_width+fm.descent(), text_height));
|
p.drawRect(QRect(text_x-fm.descent()/2, rect_y, text_width+fm.descent(), text_height));
|
||||||
p.setBrush(color_val->get_color_value(timecode));
|
p.setBrush(color_val->get_color_value(timecode));
|
||||||
p.drawPath(path);
|
p.drawPath(path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,21 +9,21 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) {
|
ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) {
|
||||||
type_val = add_row("Type:")->add_field(EFFECT_FIELD_COMBO, "type");
|
type_val = add_row("Type")->add_field(EFFECT_FIELD_COMBO, "type");
|
||||||
type_val->add_combo_item("Sine", TONE_TYPE_SINE);
|
type_val->add_combo_item("Sine", TONE_TYPE_SINE);
|
||||||
|
|
||||||
freq_val = add_row("Frequency:")->add_field(EFFECT_FIELD_DOUBLE, "frequency");
|
freq_val = add_row("Frequency")->add_field(EFFECT_FIELD_DOUBLE, "frequency");
|
||||||
freq_val->set_double_minimum_value(20);
|
freq_val->set_double_minimum_value(20);
|
||||||
freq_val->set_double_maximum_value(20000);
|
freq_val->set_double_maximum_value(20000);
|
||||||
freq_val->set_double_default_value(1000);
|
freq_val->set_double_default_value(1000);
|
||||||
|
|
||||||
amount_val = add_row("Amount:")->add_field(EFFECT_FIELD_DOUBLE, "amount");
|
amount_val = add_row("Amount")->add_field(EFFECT_FIELD_DOUBLE, "amount");
|
||||||
amount_val->set_double_minimum_value(0);
|
amount_val->set_double_minimum_value(0);
|
||||||
amount_val->set_double_maximum_value(100);
|
amount_val->set_double_maximum_value(100);
|
||||||
amount_val->set_double_default_value(25);
|
amount_val->set_double_default_value(25);
|
||||||
|
|
||||||
mix_val = add_row("Mix:")->add_field(EFFECT_FIELD_BOOL, "mix");
|
mix_val = add_row("Mix")->add_field(EFFECT_FIELD_BOOL, "mix");
|
||||||
mix_val->set_bool_value(true);
|
mix_val->set_bool_value(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
|
void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) {
|
||||||
|
|||||||
@@ -28,147 +28,177 @@
|
|||||||
#define BLEND_MODE_MULTIPLY 2
|
#define BLEND_MODE_MULTIPLY 2
|
||||||
#define BLEND_MODE_OVERLAY 3
|
#define BLEND_MODE_OVERLAY 3
|
||||||
|
|
||||||
TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) {
|
||||||
enable_coords = true;
|
enable_coords = true;
|
||||||
|
|
||||||
EffectRow* position_row = add_row("Position:");
|
EffectRow* position_row = add_row("Position");
|
||||||
position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X
|
position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X
|
||||||
position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y
|
position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y
|
||||||
|
|
||||||
EffectRow* scale_row = add_row("Scale:");
|
EffectRow* scale_row = add_row("Scale");
|
||||||
scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected)
|
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_minimum_value(0);
|
||||||
scale_x->set_double_maximum_value(3000);
|
scale_x->set_double_maximum_value(3000);
|
||||||
scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected)
|
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_minimum_value(0);
|
||||||
scale_y->set_double_maximum_value(3000);
|
scale_y->set_double_maximum_value(3000);
|
||||||
|
|
||||||
EffectRow* uniform_scale_row = add_row("Uniform Scale:");
|
EffectRow* uniform_scale_row = add_row("Uniform Scale");
|
||||||
uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option
|
uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option
|
||||||
|
|
||||||
EffectRow* rotation_row = add_row("Rotation:");
|
EffectRow* rotation_row = add_row("Rotation");
|
||||||
rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
|
rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation");
|
||||||
|
|
||||||
EffectRow* anchor_point_row = add_row("Anchor Point:");
|
EffectRow* anchor_point_row = add_row("Anchor Point");
|
||||||
anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchorx"); // anchor point X
|
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
|
anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchory"); // anchor point Y
|
||||||
|
|
||||||
EffectRow* opacity_row = add_row("Opacity:");
|
EffectRow* opacity_row = add_row("Opacity");
|
||||||
opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity
|
opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity
|
||||||
opacity->set_double_minimum_value(0);
|
opacity->set_double_minimum_value(0);
|
||||||
opacity->set_double_maximum_value(100);
|
opacity->set_double_maximum_value(100);
|
||||||
|
|
||||||
EffectRow* blend_mode_row = add_row("Blend Mode:");
|
EffectRow* blend_mode_row = add_row("Blend Mode");
|
||||||
blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode"); // blend mode
|
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("Normal", BLEND_MODE_NORMAL);
|
||||||
blend_mode_box->add_combo_item("Overlay", BLEND_MODE_OVERLAY);
|
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("Screen", BLEND_MODE_SCREEN);
|
||||||
blend_mode_box->add_combo_item("Multiply", BLEND_MODE_MULTIPLY);
|
blend_mode_box->add_combo_item("Multiply", BLEND_MODE_MULTIPLY);
|
||||||
|
|
||||||
// set up gizmos
|
// set up gizmos
|
||||||
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
top_left_gizmo->set_cursor(Qt::SizeFDiagCursor);
|
top_left_gizmo->set_cursor(Qt::SizeFDiagCursor);
|
||||||
top_left_gizmo->x_field1 = scale_x;
|
top_left_gizmo->x_field1 = scale_x;
|
||||||
|
|
||||||
top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
top_center_gizmo->set_cursor(Qt::SizeVerCursor);
|
top_center_gizmo->set_cursor(Qt::SizeVerCursor);
|
||||||
top_center_gizmo->y_field1 = scale_x;
|
top_center_gizmo->y_field1 = scale_x;
|
||||||
|
|
||||||
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
top_right_gizmo->set_cursor(Qt::SizeBDiagCursor);
|
top_right_gizmo->set_cursor(Qt::SizeBDiagCursor);
|
||||||
top_right_gizmo->x_field1 = scale_x;
|
top_right_gizmo->x_field1 = scale_x;
|
||||||
|
|
||||||
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor);
|
bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor);
|
||||||
bottom_left_gizmo->x_field1 = scale_x;
|
bottom_left_gizmo->x_field1 = scale_x;
|
||||||
|
|
||||||
bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
bottom_center_gizmo->set_cursor(Qt::SizeVerCursor);
|
bottom_center_gizmo->set_cursor(Qt::SizeVerCursor);
|
||||||
bottom_center_gizmo->y_field1 = scale_x;
|
bottom_center_gizmo->y_field1 = scale_x;
|
||||||
|
|
||||||
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor);
|
bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor);
|
||||||
bottom_right_gizmo->x_field1 = scale_x;
|
bottom_right_gizmo->x_field1 = scale_x;
|
||||||
|
|
||||||
left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
left_center_gizmo->set_cursor(Qt::SizeHorCursor);
|
left_center_gizmo->set_cursor(Qt::SizeHorCursor);
|
||||||
left_center_gizmo->x_field1 = scale_x;
|
left_center_gizmo->x_field1 = scale_x;
|
||||||
|
|
||||||
right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
right_center_gizmo->set_cursor(Qt::SizeHorCursor);
|
right_center_gizmo->set_cursor(Qt::SizeHorCursor);
|
||||||
right_center_gizmo->x_field1 = scale_x;
|
right_center_gizmo->x_field1 = scale_x;
|
||||||
|
|
||||||
anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET);
|
anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET);
|
||||||
anchor_gizmo->set_cursor(Qt::SizeAllCursor);
|
anchor_gizmo->set_cursor(Qt::SizeAllCursor);
|
||||||
anchor_gizmo->x_field1 = anchor_x_box;
|
anchor_gizmo->x_field1 = anchor_x_box;
|
||||||
anchor_gizmo->y_field1 = anchor_y_box;
|
anchor_gizmo->y_field1 = anchor_y_box;
|
||||||
anchor_gizmo->x_field2 = position_x;
|
anchor_gizmo->x_field2 = position_x;
|
||||||
anchor_gizmo->y_field2 = position_y;
|
anchor_gizmo->y_field2 = position_y;
|
||||||
|
|
||||||
rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT);
|
||||||
rotate_gizmo->color = Qt::green;
|
rotate_gizmo->color = Qt::green;
|
||||||
rotate_gizmo->set_cursor(Qt::SizeAllCursor);
|
rotate_gizmo->set_cursor(Qt::SizeAllCursor);
|
||||||
rotate_gizmo->x_field1 = rotation;
|
rotate_gizmo->x_field1 = rotation;
|
||||||
|
|
||||||
rect_gizmo = add_gizmo(GIZMO_TYPE_POLY);
|
rect_gizmo = add_gizmo(GIZMO_TYPE_POLY);
|
||||||
rect_gizmo->x_field1 = position_x;
|
rect_gizmo->x_field1 = position_x;
|
||||||
rect_gizmo->y_field1 = position_y;
|
rect_gizmo->y_field1 = position_y;
|
||||||
|
|
||||||
connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
|
connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool)));
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
uniform_scale_field->set_bool_value(true);
|
uniform_scale_field->set_bool_value(true);
|
||||||
blend_mode_box->set_combo_index(0);
|
blend_mode_box->set_combo_index(0);
|
||||||
|
set = false;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void adjust_field(EffectField* field, double old_offset, double new_offset) {
|
||||||
|
if (field->keyframes.size() > 0) {
|
||||||
|
for (int i=0;i<field->keyframes.size();i++) {
|
||||||
|
field->keyframes[i].data = field->keyframes.at(i).data.toDouble() - old_offset + new_offset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
field->set_current_data(field->get_current_data().toDouble() - old_offset + new_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TransformEffect::refresh() {
|
void TransformEffect::refresh() {
|
||||||
if (parent_clip != NULL && parent_clip->sequence != NULL) {
|
if (parent_clip != NULL && parent_clip->sequence != NULL) {
|
||||||
double default_pos_x = parent_clip->sequence->width/2;
|
double new_default_pos_x = parent_clip->sequence->width/2;
|
||||||
double default_pos_y = parent_clip->sequence->height/2;
|
double new_default_pos_y = parent_clip->sequence->height/2;
|
||||||
|
|
||||||
|
/*if (set) {
|
||||||
|
adjust_field(position_x, default_pos_x, new_default_pos_x);
|
||||||
|
adjust_field(position_y, default_pos_y, new_default_pos_y);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
default_pos_x = new_default_pos_x;
|
||||||
|
default_pos_y = new_default_pos_y;
|
||||||
|
|
||||||
position_x->set_double_default_value(default_pos_x);
|
position_x->set_double_default_value(default_pos_x);
|
||||||
position_y->set_double_default_value(default_pos_y);
|
position_y->set_double_default_value(default_pos_y);
|
||||||
scale_x->set_double_default_value(100);
|
scale_x->set_double_default_value(100);
|
||||||
scale_y->set_double_default_value(100);
|
scale_y->set_double_default_value(100);
|
||||||
|
|
||||||
default_anchor_x = parent_clip->getWidth()/2;
|
int new_default_anchor_x = parent_clip->getWidth()/2;
|
||||||
default_anchor_y = parent_clip->getHeight()/2;
|
int new_default_anchor_y = parent_clip->getHeight()/2;
|
||||||
|
|
||||||
if (default_anchor_x == 0) default_anchor_x = default_pos_x;
|
if (new_default_anchor_x == 0) new_default_anchor_x = default_pos_x;
|
||||||
if (default_anchor_y == 0) default_anchor_y = default_pos_y;
|
if (new_default_anchor_y == 0) new_default_anchor_y = default_pos_y;
|
||||||
|
|
||||||
|
// adjust anchors for new size
|
||||||
|
if (set) {
|
||||||
|
adjust_field(anchor_x_box, default_anchor_x, new_default_anchor_x);
|
||||||
|
adjust_field(anchor_y_box, default_anchor_y, new_default_anchor_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
default_anchor_x = new_default_anchor_x;
|
||||||
|
default_anchor_y = new_default_anchor_y;
|
||||||
|
|
||||||
anchor_x_box->set_double_default_value(default_anchor_x);
|
anchor_x_box->set_double_default_value(default_anchor_x);
|
||||||
anchor_y_box->set_double_default_value(default_anchor_y);
|
anchor_y_box->set_double_default_value(default_anchor_y);
|
||||||
opacity->set_double_default_value(100);
|
opacity->set_double_default_value(100);
|
||||||
|
|
||||||
double x_percent_multipler = 200.0 / parent_clip->sequence->width;
|
double x_percent_multipler = 200.0 / parent_clip->sequence->width;
|
||||||
double y_percent_multipler = 200.0 / parent_clip->sequence->height;
|
double y_percent_multipler = 200.0 / parent_clip->sequence->height;
|
||||||
top_left_gizmo->x_field_multi1 = -x_percent_multipler;
|
top_left_gizmo->x_field_multi1 = -x_percent_multipler;
|
||||||
top_left_gizmo->y_field_multi1 = -y_percent_multipler;
|
top_left_gizmo->y_field_multi1 = -y_percent_multipler;
|
||||||
top_center_gizmo->y_field_multi1 = -y_percent_multipler;
|
top_center_gizmo->y_field_multi1 = -y_percent_multipler;
|
||||||
top_right_gizmo->x_field_multi1 = x_percent_multipler;
|
top_right_gizmo->x_field_multi1 = x_percent_multipler;
|
||||||
top_right_gizmo->y_field_multi1 = -y_percent_multipler;
|
top_right_gizmo->y_field_multi1 = -y_percent_multipler;
|
||||||
bottom_left_gizmo->x_field_multi1 = -x_percent_multipler;
|
bottom_left_gizmo->x_field_multi1 = -x_percent_multipler;
|
||||||
bottom_left_gizmo->y_field_multi1 = y_percent_multipler;
|
bottom_left_gizmo->y_field_multi1 = y_percent_multipler;
|
||||||
bottom_center_gizmo->y_field_multi1 = y_percent_multipler;
|
bottom_center_gizmo->y_field_multi1 = y_percent_multipler;
|
||||||
bottom_right_gizmo->x_field_multi1 = x_percent_multipler;
|
bottom_right_gizmo->x_field_multi1 = x_percent_multipler;
|
||||||
bottom_right_gizmo->y_field_multi1 = y_percent_multipler;
|
bottom_right_gizmo->y_field_multi1 = y_percent_multipler;
|
||||||
left_center_gizmo->x_field_multi1 = -x_percent_multipler;
|
left_center_gizmo->x_field_multi1 = -x_percent_multipler;
|
||||||
right_center_gizmo->x_field_multi1 = x_percent_multipler;
|
right_center_gizmo->x_field_multi1 = x_percent_multipler;
|
||||||
rotate_gizmo->x_field_multi1 = x_percent_multipler;
|
rotate_gizmo->x_field_multi1 = x_percent_multipler;
|
||||||
|
|
||||||
|
set = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformEffect::toggle_uniform_scale(bool enabled) {
|
void TransformEffect::toggle_uniform_scale(bool enabled) {
|
||||||
scale_y->set_enabled(!enabled);
|
scale_y->set_enabled(!enabled);
|
||||||
|
|
||||||
top_center_gizmo->y_field1 = enabled ? scale_x : scale_y;
|
top_center_gizmo->y_field1 = enabled ? scale_x : scale_y;
|
||||||
bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y;
|
bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y;
|
||||||
top_left_gizmo->y_field1 = enabled ? NULL : scale_y;
|
top_left_gizmo->y_field1 = enabled ? NULL : scale_y;
|
||||||
top_right_gizmo->y_field1 = enabled ? NULL : scale_y;
|
top_right_gizmo->y_field1 = enabled ? NULL : scale_y;
|
||||||
bottom_left_gizmo->y_field1 = enabled ? NULL : scale_y;
|
bottom_left_gizmo->y_field1 = enabled ? NULL : scale_y;
|
||||||
bottom_right_gizmo->y_field1 = enabled ? NULL : scale_y;
|
bottom_right_gizmo->y_field1 = enabled ? NULL : scale_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int data) {
|
void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int data) {
|
||||||
@@ -188,51 +218,51 @@ void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, i
|
|||||||
coords.vertexBottomRightY -= anchor_y_offset;
|
coords.vertexBottomRightY -= anchor_y_offset;
|
||||||
|
|
||||||
// rotation
|
// rotation
|
||||||
glRotatef(rotation->get_double_value(timecode), 0, 0, 1);
|
glRotatef(rotation->get_double_value(timecode), 0, 0, 1);
|
||||||
|
|
||||||
// scale
|
// scale
|
||||||
float sx = scale_x->get_double_value(timecode)*0.01;
|
float sx = scale_x->get_double_value(timecode)*0.01;
|
||||||
float sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01;
|
float sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01;
|
||||||
glScalef(sx, sy, 1);
|
glScalef(sx, sy, 1);
|
||||||
|
|
||||||
// blend mode
|
// blend mode
|
||||||
switch (blend_mode_box->get_combo_data(timecode).toInt()) {
|
switch (blend_mode_box->get_combo_data(timecode).toInt()) {
|
||||||
case BLEND_MODE_NORMAL:
|
case BLEND_MODE_NORMAL:
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
break;
|
break;
|
||||||
case BLEND_MODE_OVERLAY:
|
case BLEND_MODE_OVERLAY:
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||||
break;
|
break;
|
||||||
case BLEND_MODE_SCREEN:
|
case BLEND_MODE_SCREEN:
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||||
break;
|
break;
|
||||||
case BLEND_MODE_MULTIPLY:
|
case BLEND_MODE_MULTIPLY:
|
||||||
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dout << "[ERROR] Invalid blend mode. This is a bug - please contact developers";
|
dout << "[ERROR] Invalid blend mode. This is a bug - please contact developers";
|
||||||
}
|
}
|
||||||
|
|
||||||
// opacity
|
// opacity
|
||||||
float color[4];
|
float color[4];
|
||||||
glGetFloatv(GL_CURRENT_COLOR, color);
|
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) {
|
void TransformEffect::gizmo_draw(double timecode, GLTextureCoords& coords) {
|
||||||
top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
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_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);
|
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));
|
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_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_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);
|
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));
|
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));
|
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[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY);
|
||||||
rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY);
|
||||||
rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY);
|
||||||
rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ private:
|
|||||||
|
|
||||||
int default_anchor_x;
|
int default_anchor_x;
|
||||||
int default_anchor_y;
|
int default_anchor_y;
|
||||||
|
double default_pos_x;
|
||||||
|
double default_pos_y;
|
||||||
|
bool set;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRANSFORMEFFECT_H
|
#endif // TRANSFORMEFFECT_H
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
#include "ui/collapsiblewidget.h"
|
#include "ui/collapsiblewidget.h"
|
||||||
|
|
||||||
VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) {
|
||||||
EffectRow* volume_row = add_row("Volume:");
|
EffectRow* volume_row = add_row("Volume");
|
||||||
volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume");
|
volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume");
|
||||||
volume_val->set_double_minimum_value(0);
|
volume_val->set_double_minimum_value(0);
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
volume_val->set_double_default_value(100);
|
volume_val->set_double_default_value(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) {
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#define SAVE_VERSION 181124 // YYMMDD
|
#define SAVE_VERSION 190104 // YYMMDD
|
||||||
#define MIN_SAVE_VERSION 181114 // lowest compatible project version
|
#define MIN_SAVE_VERSION 190104 // lowest compatible project version
|
||||||
|
|
||||||
#define TIMECODE_DROP 0
|
#define TIMECODE_DROP 0
|
||||||
#define TIMECODE_NONDROP 1
|
#define TIMECODE_NONDROP 1
|
||||||
|
|||||||
+1
-1
@@ -237,7 +237,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) {
|
|||||||
} else if (m->url.contains('%')) {
|
} else if (m->url.contains('%')) {
|
||||||
// hack for image sequences (qt won't be able to find the URL with %, but ffmpeg may)
|
// hack for image sequences (qt won't be able to find the URL with %, but ffmpeg may)
|
||||||
m->url = internal_proj_dir_test;
|
m->url = internal_proj_dir_test;
|
||||||
dout << "[INFO] Guess image sequence" << attr.value().toString() << "path to project's current directory";
|
dout << "[INFO] Guess image sequence" << attr.value().toString() << "path to project's internal directory";
|
||||||
} else {
|
} else {
|
||||||
dout << "[INFO] Failed to match" << attr.value().toString() << "to file";
|
dout << "[INFO] Failed to match" << attr.value().toString() << "to file";
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-3
@@ -1,15 +1,54 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
int lerp(int a, int b, double t) {
|
int lerp(int a, int b, double t) {
|
||||||
return qRound(((1.0 - t) * a) + (t * b));
|
return qRound(((1.0 - t) * a) + (t * b));
|
||||||
}
|
}
|
||||||
|
|
||||||
float float_lerp(float a, float b, float t) {
|
float float_lerp(float a, float b, float t) {
|
||||||
return ((1.0F - t) * a) + (t * b);
|
return ((1.0F - t) * a) + (t * b);
|
||||||
}
|
}
|
||||||
|
|
||||||
double double_lerp(double a, double b, double t) {
|
double double_lerp(double a, double b, double t) {
|
||||||
return ((1.0 - t) * a) + (t * b);
|
return ((1.0 - t) * a) + (t * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
double quad_from_t(double a, double b, double c, double t) {
|
||||||
|
return qPow(1.0 - t, 2)*a + 2*(1.0 - t)*t*b + qPow(t, 2)*c;
|
||||||
|
}
|
||||||
|
|
||||||
|
double quad_t_from_x(double x, double a, double b, double c) {
|
||||||
|
return (a - b + qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c);
|
||||||
|
// alt: return (a - b - qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
double cubic_from_t(double a, double b, double c, double d, double t) {
|
||||||
|
return qPow(1.0 - t, 3)*a + 3*qPow(1.0 - t, 2)*t*b + 3*(1.0 - t)*qPow(t, 2)*c + qPow(t, 3)*d;
|
||||||
|
}
|
||||||
|
|
||||||
|
double cubic_t_from_x(double x_target, double a, double b, double c, double d) {
|
||||||
|
double tolerance = 0.0001;
|
||||||
|
|
||||||
|
double lower = 0.0;
|
||||||
|
double upper = 1.0;
|
||||||
|
|
||||||
|
double percent = 0.5;
|
||||||
|
double x = cubic_from_t(a, b, c, d, percent);
|
||||||
|
|
||||||
|
while (qAbs(x_target - x) > tolerance) {
|
||||||
|
if (x_target > x) {
|
||||||
|
lower = percent;
|
||||||
|
} else {
|
||||||
|
upper = percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
percent = (upper + lower) / 2.0;
|
||||||
|
x = cubic_from_t(a, b, c, d, percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return percent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,10 @@
|
|||||||
int lerp(int a, int b, double t);
|
int lerp(int a, int b, double t);
|
||||||
float float_lerp(float a, float b, float t);
|
float float_lerp(float a, float b, float t);
|
||||||
double double_lerp(double a, double b, double t);
|
double double_lerp(double a, double b, double t);
|
||||||
|
double quad_from_t(double a, double b, double c, double t);
|
||||||
|
double quad_t_from_x(double x, double a, double b, double c);
|
||||||
|
double cubic_from_t(double a, double b, double c, double d, double t);
|
||||||
|
double cubic_t_from_x(double x_target, double a, double b, double c, double d);
|
||||||
|
double solveCubicBezier(double p0, double p1, double p2, double p3, double x);
|
||||||
|
|
||||||
#endif // MATH_H
|
#endif // MATH_H
|
||||||
|
|||||||
+78
-71
@@ -19,6 +19,7 @@
|
|||||||
#include "panels/effectcontrols.h"
|
#include "panels/effectcontrols.h"
|
||||||
#include "panels/viewer.h"
|
#include "panels/viewer.h"
|
||||||
#include "panels/timeline.h"
|
#include "panels/timeline.h"
|
||||||
|
#include "panels/grapheditor.h"
|
||||||
|
|
||||||
#include "dialogs/aboutdialog.h"
|
#include "dialogs/aboutdialog.h"
|
||||||
#include "dialogs/newsequencedialog.h"
|
#include "dialogs/newsequencedialog.h"
|
||||||
@@ -63,31 +64,28 @@ void MainWindow::setup_layout(bool reset) {
|
|||||||
panel_footage_viewer->show();
|
panel_footage_viewer->show();
|
||||||
panel_sequence_viewer->show();
|
panel_sequence_viewer->show();
|
||||||
panel_timeline->show();
|
panel_timeline->show();
|
||||||
|
panel_graph_editor->hide();
|
||||||
|
|
||||||
bool load_default = true;
|
addDockWidget(Qt::TopDockWidgetArea, panel_project);
|
||||||
|
addDockWidget(Qt::TopDockWidgetArea, panel_footage_viewer);
|
||||||
/*if (!reset) {
|
tabifyDockWidget(panel_footage_viewer, panel_effect_controls);
|
||||||
QFile panel_config(get_data_path() + "/layout");
|
panel_footage_viewer->raise();
|
||||||
if (panel_config.exists() && panel_config.open(QFile::ReadOnly)) {
|
addDockWidget(Qt::TopDockWidgetArea, panel_sequence_viewer);
|
||||||
if (restoreState(panel_config.readAll(), 0)) {
|
addDockWidget(Qt::BottomDockWidgetArea, panel_timeline);
|
||||||
load_default = false;
|
panel_graph_editor->setFloating(true);
|
||||||
}
|
|
||||||
panel_config.close();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (load_default) {
|
|
||||||
addDockWidget(Qt::TopDockWidgetArea, panel_project);
|
|
||||||
addDockWidget(Qt::TopDockWidgetArea, panel_footage_viewer);
|
|
||||||
tabifyDockWidget(panel_footage_viewer, panel_effect_controls);
|
|
||||||
panel_footage_viewer->raise();
|
|
||||||
addDockWidget(Qt::TopDockWidgetArea, panel_sequence_viewer);
|
|
||||||
addDockWidget(Qt::BottomDockWidgetArea, panel_timeline);
|
|
||||||
|
|
||||||
// workaround for strange Qt dock bug (see https://bugreports.qt.io/browse/QTBUG-65592)
|
// workaround for strange Qt dock bug (see https://bugreports.qt.io/browse/QTBUG-65592)
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
||||||
resizeDocks({panel_project}, {40}, Qt::Horizontal);
|
resizeDocks({panel_project}, {40}, Qt::Horizontal);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// load panels from file
|
||||||
|
if (!reset) {
|
||||||
|
QFile panel_config(get_data_path() + "/layout");
|
||||||
|
if (panel_config.exists() && panel_config.open(QFile::ReadOnly)) {
|
||||||
|
restoreState(panel_config.readAll(), 0);
|
||||||
|
panel_config.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layout()->update();
|
layout()->update();
|
||||||
@@ -195,12 +193,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO maybe replace these with non-pointers later on?
|
alloc_panels(this);
|
||||||
panel_sequence_viewer = new Viewer(this);
|
|
||||||
panel_footage_viewer = new Viewer(this);
|
|
||||||
panel_project = new Project(this);
|
|
||||||
panel_effect_controls = new EffectControls(this);
|
|
||||||
panel_timeline = new Timeline(this);
|
|
||||||
|
|
||||||
QStatusBar* statusBar = new QStatusBar(this);
|
QStatusBar* statusBar = new QStatusBar(this);
|
||||||
statusBar->showMessage("Welcome to " + appName);
|
statusBar->showMessage("Welcome to " + appName);
|
||||||
@@ -213,6 +206,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
autorecovery_filename = data_dir + "/autorecovery.ove";
|
autorecovery_filename = data_dir + "/autorecovery.ove";
|
||||||
if (QFile::exists(autorecovery_filename)) {
|
if (QFile::exists(autorecovery_filename)) {
|
||||||
if (QMessageBox::question(NULL, "Auto-recovery", "Olive didn't close properly and an autorecovery file was detected. Would you like to open it?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
if (QMessageBox::question(NULL, "Auto-recovery", "Olive didn't close properly and an autorecovery file was detected. Would you like to open it?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
||||||
|
enable_launch_with_project = false;
|
||||||
open_project_worker(autorecovery_filename, true);
|
open_project_worker(autorecovery_filename, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,45 +221,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() {
|
MainWindow::~MainWindow() {
|
||||||
panel_effect_controls->clear_effects(true);
|
free_panels();
|
||||||
panel_sequence_viewer->viewer_widget->delete_function();
|
|
||||||
panel_footage_viewer->viewer_widget->delete_function();
|
|
||||||
|
|
||||||
set_sequence(NULL);
|
|
||||||
|
|
||||||
QString data_dir = get_data_path();
|
|
||||||
if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) {
|
|
||||||
if (QFile::exists(autorecovery_filename)) {
|
|
||||||
QFile::rename(autorecovery_filename, autorecovery_filename + "." + QDateTime::currentDateTimeUtc().toString("yyyyMMddHHmmss"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!config_dir.isEmpty()) {
|
|
||||||
// save settings
|
|
||||||
config.save(config_dir);
|
|
||||||
|
|
||||||
// save panel layout
|
|
||||||
QFile panel_config(data_dir + "/layout");
|
|
||||||
if (panel_config.open(QFile::WriteOnly)) {
|
|
||||||
panel_config.write(saveState(0));
|
|
||||||
panel_config.close();
|
|
||||||
} else {
|
|
||||||
dout << "[ERROR] Failed to save layout";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_audio();
|
|
||||||
|
|
||||||
delete panel_sequence_viewer;
|
|
||||||
panel_sequence_viewer = NULL;
|
|
||||||
delete panel_footage_viewer;
|
|
||||||
panel_footage_viewer = NULL;
|
|
||||||
delete panel_project;
|
|
||||||
panel_project = NULL;
|
|
||||||
delete panel_effect_controls;
|
|
||||||
panel_effect_controls = NULL;
|
|
||||||
delete panel_timeline;
|
|
||||||
panel_timeline = NULL;
|
|
||||||
|
|
||||||
close_debug();
|
close_debug();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,12 +259,16 @@ void MainWindow::delete_slot() {
|
|||||||
panel_project->delete_selected_media();
|
panel_project->delete_selected_media();
|
||||||
} else if (panel_effect_controls->keyframe_focus()) {
|
} else if (panel_effect_controls->keyframe_focus()) {
|
||||||
panel_effect_controls->delete_selected_keyframes();
|
panel_effect_controls->delete_selected_keyframes();
|
||||||
|
} else if (panel_graph_editor->view_is_focused()) {
|
||||||
|
panel_graph_editor->delete_selected_keys();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::select_all() {
|
void MainWindow::select_all() {
|
||||||
if (panel_timeline->focused()) {
|
if (panel_timeline->focused()) {
|
||||||
panel_timeline->select_all();
|
panel_timeline->select_all();
|
||||||
|
} else if (panel_graph_editor->view_is_focused()) {
|
||||||
|
panel_graph_editor->select_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,6 +614,10 @@ void MainWindow::setup_menus() {
|
|||||||
window_timeline_action->setCheckable(true);
|
window_timeline_action->setCheckable(true);
|
||||||
window_timeline_action->setData(reinterpret_cast<quintptr>(panel_timeline));
|
window_timeline_action->setData(reinterpret_cast<quintptr>(panel_timeline));
|
||||||
|
|
||||||
|
QAction* window_graph_editor_action = window_menu->addAction("Graph Editor", this, SLOT(toggle_panel_visibility()));
|
||||||
|
window_graph_editor_action->setCheckable(true);
|
||||||
|
window_graph_editor_action->setData(reinterpret_cast<quintptr>(panel_graph_editor));
|
||||||
|
|
||||||
QAction* window_footageviewer_action = window_menu->addAction("Footage Viewer", this, SLOT(toggle_panel_visibility()));
|
QAction* window_footageviewer_action = window_menu->addAction("Footage Viewer", this, SLOT(toggle_panel_visibility()));
|
||||||
window_footageviewer_action->setCheckable(true);
|
window_footageviewer_action->setCheckable(true);
|
||||||
window_footageviewer_action->setData(reinterpret_cast<quintptr>(panel_footage_viewer));
|
window_footageviewer_action->setData(reinterpret_cast<quintptr>(panel_footage_viewer));
|
||||||
@@ -778,7 +742,7 @@ void MainWindow::setup_menus() {
|
|||||||
tools_menu->addAction("Preferences", this, SLOT(preferences()), QKeySequence("Ctrl+."));
|
tools_menu->addAction("Preferences", this, SLOT(preferences()), QKeySequence("Ctrl+."));
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
tools_menu->addAction("Clear Undo", this, SLOT(clear_undo_stack()), QKeySequence("Ctrl+."));
|
tools_menu->addAction("Clear Undo", this, SLOT(clear_undo_stack()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// INITIALIZE HELP MENU
|
// INITIALIZE HELP MENU
|
||||||
@@ -812,6 +776,34 @@ void MainWindow::updateTitle(const QString& url) {
|
|||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *e) {
|
void MainWindow::closeEvent(QCloseEvent *e) {
|
||||||
if (can_close_project()) {
|
if (can_close_project()) {
|
||||||
|
panel_effect_controls->clear_effects(true);
|
||||||
|
|
||||||
|
set_sequence(NULL);
|
||||||
|
|
||||||
|
panel_footage_viewer->set_main_sequence();
|
||||||
|
|
||||||
|
QString data_dir = get_data_path();
|
||||||
|
if (!data_dir.isEmpty() && !autorecovery_filename.isEmpty()) {
|
||||||
|
if (QFile::exists(autorecovery_filename)) {
|
||||||
|
QFile::rename(autorecovery_filename, autorecovery_filename + "." + QDateTime::currentDateTimeUtc().toString("yyyyMMddHHmmss"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!config_dir.isEmpty()) {
|
||||||
|
// save settings
|
||||||
|
config.save(config_dir);
|
||||||
|
|
||||||
|
// save panel layout
|
||||||
|
QFile panel_config(data_dir + "/layout");
|
||||||
|
if (panel_config.open(QFile::WriteOnly)) {
|
||||||
|
panel_config.write(saveState(0));
|
||||||
|
panel_config.close();
|
||||||
|
} else {
|
||||||
|
dout << "[ERROR] Failed to save layout";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_audio();
|
||||||
|
|
||||||
e->accept();
|
e->accept();
|
||||||
} else {
|
} else {
|
||||||
e->ignore();
|
e->ignore();
|
||||||
@@ -859,7 +851,10 @@ void MainWindow::reset_layout() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::go_to_start() {
|
void MainWindow::go_to_start() {
|
||||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
if (panel_timeline->focused()
|
||||||
|
|| panel_sequence_viewer->is_focused()
|
||||||
|
|| panel_effect_controls->keyframe_focus()
|
||||||
|
|| panel_graph_editor->view_is_focused()) {
|
||||||
panel_sequence_viewer->go_to_start();
|
panel_sequence_viewer->go_to_start();
|
||||||
} else if (panel_footage_viewer->is_focused()) {
|
} else if (panel_footage_viewer->is_focused()) {
|
||||||
panel_footage_viewer->go_to_start();
|
panel_footage_viewer->go_to_start();
|
||||||
@@ -867,7 +862,10 @@ void MainWindow::go_to_start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::prev_frame() {
|
void MainWindow::prev_frame() {
|
||||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
if (panel_timeline->focused()
|
||||||
|
|| panel_sequence_viewer->is_focused()
|
||||||
|
|| panel_effect_controls->keyframe_focus()
|
||||||
|
|| panel_graph_editor->view_is_focused()) {
|
||||||
panel_sequence_viewer->previous_frame();
|
panel_sequence_viewer->previous_frame();
|
||||||
} else if (panel_footage_viewer->is_focused()) {
|
} else if (panel_footage_viewer->is_focused()) {
|
||||||
panel_footage_viewer->previous_frame();
|
panel_footage_viewer->previous_frame();
|
||||||
@@ -875,7 +873,10 @@ void MainWindow::prev_frame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::next_frame() {
|
void MainWindow::next_frame() {
|
||||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
if (panel_timeline->focused()
|
||||||
|
|| panel_sequence_viewer->is_focused()
|
||||||
|
|| panel_effect_controls->keyframe_focus()
|
||||||
|
|| panel_graph_editor->view_is_focused()) {
|
||||||
panel_sequence_viewer->next_frame();
|
panel_sequence_viewer->next_frame();
|
||||||
} else if (panel_footage_viewer->is_focused()) {
|
} else if (panel_footage_viewer->is_focused()) {
|
||||||
panel_footage_viewer->next_frame();
|
panel_footage_viewer->next_frame();
|
||||||
@@ -883,7 +884,10 @@ void MainWindow::next_frame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::go_to_end() {
|
void MainWindow::go_to_end() {
|
||||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
if (panel_timeline->focused()
|
||||||
|
|| panel_sequence_viewer->is_focused()
|
||||||
|
|| panel_effect_controls->keyframe_focus()
|
||||||
|
|| panel_graph_editor->view_is_focused()) {
|
||||||
panel_sequence_viewer->go_to_end();
|
panel_sequence_viewer->go_to_end();
|
||||||
} else if (panel_footage_viewer->is_focused()) {
|
} else if (panel_footage_viewer->is_focused()) {
|
||||||
panel_footage_viewer->go_to_end();
|
panel_footage_viewer->go_to_end();
|
||||||
@@ -891,7 +895,10 @@ void MainWindow::go_to_end() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::playpause() {
|
void MainWindow::playpause() {
|
||||||
if (panel_timeline->focused() || panel_sequence_viewer->is_focused() || panel_effect_controls->keyframe_focus()) {
|
if (panel_timeline->focused()
|
||||||
|
|| panel_sequence_viewer->is_focused()
|
||||||
|
|| panel_effect_controls->keyframe_focus()
|
||||||
|
|| panel_graph_editor->view_is_focused()) {
|
||||||
panel_sequence_viewer->toggle_play();
|
panel_sequence_viewer->toggle_play();
|
||||||
} else if (panel_footage_viewer->is_focused()) {
|
} else if (panel_footage_viewer->is_focused()) {
|
||||||
panel_footage_viewer->toggle_play();
|
panel_footage_viewer->toggle_play();
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ private slots:
|
|||||||
void menu_click_button();
|
void menu_click_button();
|
||||||
void toggle_panel_visibility();
|
void toggle_panel_visibility();
|
||||||
void set_timecode_view();
|
void set_timecode_view();
|
||||||
|
|
||||||
void open_project_worker(const QString &fn, bool autorecovery);
|
void open_project_worker(const QString &fn, bool autorecovery);
|
||||||
|
|
||||||
void load_with_launch();
|
void load_with_launch();
|
||||||
|
|||||||
+973
@@ -0,0 +1,973 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>653</width>
|
||||||
|
<height>394</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>653</width>
|
||||||
|
<height>16</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menu_File">
|
||||||
|
<property name="title">
|
||||||
|
<string>&File</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menu_New">
|
||||||
|
<property name="title">
|
||||||
|
<string>&New</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionProject"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSequence"/>
|
||||||
|
<addaction name="actionFolder"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuOpen_Recent">
|
||||||
|
<property name="title">
|
||||||
|
<string>Open Recent</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menu_New"/>
|
||||||
|
<addaction name="action_Open_Project"/>
|
||||||
|
<addaction name="menuOpen_Recent"/>
|
||||||
|
<addaction name="action_Save_Project"/>
|
||||||
|
<addaction name="actionSave_Project_As"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="action_Import"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionExport"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionExit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuEdit">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Edit</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="action_Undo"/>
|
||||||
|
<addaction name="action_Redo"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionCu_t"/>
|
||||||
|
<addaction name="actionCop_y"/>
|
||||||
|
<addaction name="action_Paste"/>
|
||||||
|
<addaction name="actionPasteInsert"/>
|
||||||
|
<addaction name="actionDuplicate"/>
|
||||||
|
<addaction name="actionDelete"/>
|
||||||
|
<addaction name="actionRipple_Delete"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSelect_All"/>
|
||||||
|
<addaction name="actionDeselect_All"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionAdd_Default_Transition"/>
|
||||||
|
<addaction name="actionLink_Unlink"/>
|
||||||
|
<addaction name="actionRipple_To_In_Point"/>
|
||||||
|
<addaction name="actionRipple_to_Out_Point"/>
|
||||||
|
<addaction name="actionEdit_to_In_Point"/>
|
||||||
|
<addaction name="actionEdit_to_Out_Point"/>
|
||||||
|
<addaction name="actionSplit_at_Playhead"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSet_In_Point"/>
|
||||||
|
<addaction name="actionSet_Out_Point"/>
|
||||||
|
<addaction name="actionClear_In_Out"/>
|
||||||
|
<addaction name="actionDelete_In_Out"/>
|
||||||
|
<addaction name="actionRipple_Delete_In_Out"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionSet_Edit_Marker"/>
|
||||||
|
<addaction name="actionEnable_Disable_Clip"/>
|
||||||
|
<addaction name="actionNest"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuWindow">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Window</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionProject_2"/>
|
||||||
|
<addaction name="actionEffect_Controls"/>
|
||||||
|
<addaction name="actionFootage_Viewer"/>
|
||||||
|
<addaction name="actionViewer"/>
|
||||||
|
<addaction name="actionTimeline"/>
|
||||||
|
<addaction name="actionGraph_Editor"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionReset_to_default_layout"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Help">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAbout"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_View">
|
||||||
|
<property name="title">
|
||||||
|
<string>&View</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuTitle_Action_Safe_Area">
|
||||||
|
<property name="title">
|
||||||
|
<string>Title/Action Safe Area</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionOff"/>
|
||||||
|
<addaction name="actionDefault"/>
|
||||||
|
<addaction name="action4_3"/>
|
||||||
|
<addaction name="action16_9"/>
|
||||||
|
<addaction name="actionCustom"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="actionTimeline_Track_Lines"/>
|
||||||
|
<addaction name="actionZoom_In"/>
|
||||||
|
<addaction name="actionZoom_out"/>
|
||||||
|
<addaction name="actionIncrease_Track_Height"/>
|
||||||
|
<addaction name="actionDecrease_Track_Height"/>
|
||||||
|
<addaction name="actionToggle_Show_All"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionFrames"/>
|
||||||
|
<addaction name="actionDrop_Frame"/>
|
||||||
|
<addaction name="actionNon_Drop_Frame"/>
|
||||||
|
<addaction name="actionMilliseconds"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="menuTitle_Action_Safe_Area"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionFull_Screen"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuPlayback">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Playback</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionGo_to_start"/>
|
||||||
|
<addaction name="actionPrevious_Frame"/>
|
||||||
|
<addaction name="actionPlay_Pause"/>
|
||||||
|
<addaction name="actionNext_Frame"/>
|
||||||
|
<addaction name="actionGo_to_End"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionGo_to_Previous_Cut"/>
|
||||||
|
<addaction name="actionGo_to_Next_Cut"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Tools">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Tools</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionPointer_Tool"/>
|
||||||
|
<addaction name="actionEdit_Tool"/>
|
||||||
|
<addaction name="actionRipple_Tool"/>
|
||||||
|
<addaction name="actionRolling_Tool"/>
|
||||||
|
<addaction name="actionRazor_Tool"/>
|
||||||
|
<addaction name="actionSlip_Tool"/>
|
||||||
|
<addaction name="actionSlide_Tool"/>
|
||||||
|
<addaction name="actionHand_Tool"/>
|
||||||
|
<addaction name="actionTransition_Tool"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionToggle_Snapping"/>
|
||||||
|
<addaction name="actionSelecting_Also_Seeks"/>
|
||||||
|
<addaction name="actionEdit_Tool_Also_Seeks"/>
|
||||||
|
<addaction name="actionEdit_Tool_Selects_Links"/>
|
||||||
|
<addaction name="actionSeek_to_the_End_of_Pastes"/>
|
||||||
|
<addaction name="actionScroll_Wheel_Zooms"/>
|
||||||
|
<addaction name="actionRectified_Waveforms"/>
|
||||||
|
<addaction name="actionEnable_Drag_Files_to_Timeline"/>
|
||||||
|
<addaction name="actionAuto_scale_by_Default"/>
|
||||||
|
<addaction name="actionEnable_Seek_to_Import"/>
|
||||||
|
<addaction name="actionAudio_Scrubbing"/>
|
||||||
|
<addaction name="actionEnable_Drop_on_Media_to_Replace"/>
|
||||||
|
<addaction name="actionEnable_Hover_Focus"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionNo_autoscroll"/>
|
||||||
|
<addaction name="actionPage_Autoscroll"/>
|
||||||
|
<addaction name="actionSmooth_Auto_scroll"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionPreferences"/>
|
||||||
|
<addaction name="actionCrash"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menu_File"/>
|
||||||
|
<addaction name="menuEdit"/>
|
||||||
|
<addaction name="menu_View"/>
|
||||||
|
<addaction name="menuPlayback"/>
|
||||||
|
<addaction name="menuWindow"/>
|
||||||
|
<addaction name="menu_Tools"/>
|
||||||
|
<addaction name="menu_Help"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
|
<action name="action_Open_Project">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Open Project</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Save_Project">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Save Project</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Project_As">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save Project &As</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Import">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Import...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Export...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+M</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExit">
|
||||||
|
<property name="text">
|
||||||
|
<string>E&xit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout">
|
||||||
|
<property name="text">
|
||||||
|
<string>About...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Undo">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Undo</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Z</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Redo">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Redo</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+Z</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCu_t">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cu&t</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+X</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCop_y">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cop&y</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+C</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Paste">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Paste</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+V</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPasteInsert">
|
||||||
|
<property name="text">
|
||||||
|
<string>Paste Insert</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+V</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete">
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Del</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelect_All">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select &All</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+A</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTimeline_Track_Lines">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Track Lines</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionProject">
|
||||||
|
<property name="text">
|
||||||
|
<string>Project...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSequence">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sequence...</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionZoom_In">
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom In</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>=</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionZoom_out">
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom Out</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>-</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionProject_2">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Project</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEffect_Controls">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Effect Controls</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionViewer">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Sequence Viewer</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTimeline">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Timeline</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRipple_Delete">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ripple Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Shift+Del</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSplit_at_Playhead">
|
||||||
|
<property name="text">
|
||||||
|
<string>Split at Playhead</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+K</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDeselect_All">
|
||||||
|
<property name="text">
|
||||||
|
<string>Deselect All</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGo_to_start">
|
||||||
|
<property name="text">
|
||||||
|
<string>Go to Start</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Home</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReset_to_default_layout">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset to default layout</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPrevious_Frame">
|
||||||
|
<property name="text">
|
||||||
|
<string>Previous Frame</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Left</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPlay_Pause">
|
||||||
|
<property name="text">
|
||||||
|
<string>Play/Pause</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Space</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNext_Frame">
|
||||||
|
<property name="text">
|
||||||
|
<string>Next Frame</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Right</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGo_to_End">
|
||||||
|
<property name="text">
|
||||||
|
<string>Go to End</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>End</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCrash">
|
||||||
|
<property name="text">
|
||||||
|
<string>Crash</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPointer_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pointer Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>V</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEdit_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>X</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRazor_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Razor Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>C</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRipple_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ripple Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>B</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRolling_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Rolling Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>N</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPreferences">
|
||||||
|
<property name="text">
|
||||||
|
<string>Preferences</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+.</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionToggle_Snapping">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Snapping</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Snapping</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSlip_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Slip Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Y</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGo_to_Previous_Cut">
|
||||||
|
<property name="text">
|
||||||
|
<string>Go to Previous Cut</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Up</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGo_to_Next_Cut">
|
||||||
|
<property name="text">
|
||||||
|
<string>Go to Next Cut</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Down</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEdit_Tool_Also_Seeks">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Tool Also Seeks</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionIncrease_Track_Height">
|
||||||
|
<property name="text">
|
||||||
|
<string>Increase Track Height</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+=</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDecrease_Track_Height">
|
||||||
|
<property name="text">
|
||||||
|
<string>Decrease Track Height</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+-</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFrames">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Frames</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDrop_Frame">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Drop-Frame</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNon_Drop_Frame">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Non-Drop Frame</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEdit_Tool_Selects_Links">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Tool Selects Links</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDuplicate">
|
||||||
|
<property name="text">
|
||||||
|
<string>Duplicate</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelecting_Also_Seeks">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Selecting Also Seeks</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSeek_to_the_End_of_Pastes">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Seek to the End of Pastes</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAdd_Default_Transition">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Default Transition</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+D</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSlide_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Slide Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>U</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFolder">
|
||||||
|
<property name="text">
|
||||||
|
<string>Folder</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionClear_Recent_List">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear Recent List</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionScroll_Wheel_Zooms">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Scroll Wheel Zooms</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionLink_Unlink">
|
||||||
|
<property name="text">
|
||||||
|
<string>Link/Unlink</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+L</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRipple_To_In_Point">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ripple to In Point</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRipple_to_Out_Point">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ripple to Out Point</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>W</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSet_In_Point">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set In Point</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>I</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSet_Out_Point">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set Out Point</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionClear_In_Out">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear In/Out</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>G</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete_In_Out">
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete In/Out</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>;</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRipple_Delete_In_Out">
|
||||||
|
<property name="text">
|
||||||
|
<string>Ripple Delete In/Out</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>'</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRectified_Waveforms">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rectified Waveforms</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDefault">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Default</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOff">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Off</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action4_3">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>4:3</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action16_9">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>16:9</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCustom">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEnable_Drag_Files_to_Timeline">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Drag Files to Timeline</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAuto_scale_by_Default">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Auto-scale by Default</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSet_Edit_Marker">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set/Edit Marker</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>M</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEnable_Disable_Clip">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable/Disable Clip</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Shift+E</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEnable_Seek_to_Import">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Seek to Import</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAudio_Scrubbing">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Audio Scrubbing</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTransition_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Transition Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>T</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEdit_to_In_Point">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit to In Point</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Alt+Q</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEdit_to_Out_Point">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit to Out Point</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Alt+W</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNest">
|
||||||
|
<property name="text">
|
||||||
|
<string>Nest</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionToggle_Show_All">
|
||||||
|
<property name="text">
|
||||||
|
<string>Toggle Show All</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>\</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEnable_Drop_on_Media_to_Replace">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Drop File on Media to Replace</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFootage_Viewer">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Footage Viewer</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNo_autoscroll">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>No Auto-scroll</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPage_Autoscroll">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Page Auto-scroll</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSmooth_Auto_scroll">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<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>
|
||||||
|
<action name="actionEnable_Hover_Focus">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Hover Focus for Zooming</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionFull_Screen">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Full Screen</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F11</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionHand_Tool">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hand Tool</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>H</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGraph_Editor">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Graph Editor</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -105,7 +105,13 @@ SOURCES += \
|
|||||||
ui/resizablescrollbar.cpp \
|
ui/resizablescrollbar.cpp \
|
||||||
ui/sourceiconview.cpp \
|
ui/sourceiconview.cpp \
|
||||||
project/sourcescommon.cpp \
|
project/sourcescommon.cpp \
|
||||||
ui/keyframenavigator.cpp
|
ui/keyframenavigator.cpp \
|
||||||
|
panels/grapheditor.cpp \
|
||||||
|
ui/graphview.cpp \
|
||||||
|
ui/keyframedrawing.cpp \
|
||||||
|
ui/clickablelabel.cpp \
|
||||||
|
project/keyframe.cpp \
|
||||||
|
ui/rectangleselect.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
mainwindow.h \
|
mainwindow.h \
|
||||||
@@ -185,7 +191,13 @@ HEADERS += \
|
|||||||
ui/resizablescrollbar.h \
|
ui/resizablescrollbar.h \
|
||||||
ui/sourceiconview.h \
|
ui/sourceiconview.h \
|
||||||
project/sourcescommon.h \
|
project/sourcescommon.h \
|
||||||
ui/keyframenavigator.h
|
ui/keyframenavigator.h \
|
||||||
|
panels/grapheditor.h \
|
||||||
|
ui/graphview.h \
|
||||||
|
ui/keyframedrawing.h \
|
||||||
|
ui/clickablelabel.h \
|
||||||
|
project/keyframe.h \
|
||||||
|
ui/rectangleselect.h
|
||||||
|
|
||||||
FORMS +=
|
FORMS +=
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "panels/project.h"
|
#include "panels/project.h"
|
||||||
#include "panels/timeline.h"
|
#include "panels/timeline.h"
|
||||||
#include "panels/viewer.h"
|
#include "panels/viewer.h"
|
||||||
|
#include "panels/grapheditor.h"
|
||||||
#include "ui/viewerwidget.h"
|
#include "ui/viewerwidget.h"
|
||||||
#include "io/clipboard.h"
|
#include "io/clipboard.h"
|
||||||
#include "ui/timelineheader.h"
|
#include "ui/timelineheader.h"
|
||||||
@@ -36,6 +37,8 @@ EffectControls::EffectControls(QWidget *parent) :
|
|||||||
panel_name("Effects: "),
|
panel_name("Effects: "),
|
||||||
mode(TA_NO_TRANSITION)
|
mode(TA_NO_TRANSITION)
|
||||||
{
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
setup_ui();
|
setup_ui();
|
||||||
|
|
||||||
init_effects();
|
init_effects();
|
||||||
@@ -210,6 +213,9 @@ void EffectControls::clear_effects(bool clear_cache) {
|
|||||||
// clear existing clips
|
// clear existing clips
|
||||||
deselect_all_effects(NULL);
|
deselect_all_effects(NULL);
|
||||||
|
|
||||||
|
// clear graph editor
|
||||||
|
if (panel_graph_editor != NULL) panel_graph_editor->set_row(NULL);
|
||||||
|
|
||||||
QVBoxLayout* video_layout = static_cast<QVBoxLayout*>(video_effect_area->layout());
|
QVBoxLayout* video_layout = static_cast<QVBoxLayout*>(video_effect_area->layout());
|
||||||
QVBoxLayout* audio_layout = static_cast<QVBoxLayout*>(audio_effect_area->layout());
|
QVBoxLayout* audio_layout = static_cast<QVBoxLayout*>(audio_effect_area->layout());
|
||||||
QLayoutItem* item;
|
QLayoutItem* item;
|
||||||
@@ -249,8 +255,6 @@ void EffectControls::open_effect(QVBoxLayout* layout, Effect* e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EffectControls::setup_ui() {
|
void EffectControls::setup_ui() {
|
||||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
|
||||||
|
|
||||||
QWidget* contents = new QWidget();
|
QWidget* contents = new QWidget();
|
||||||
|
|
||||||
QHBoxLayout* layout = new QHBoxLayout(contents);
|
QHBoxLayout* layout = new QHBoxLayout(contents);
|
||||||
|
|||||||
@@ -0,0 +1,239 @@
|
|||||||
|
#include "grapheditor.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "ui/keyframenavigator.h"
|
||||||
|
#include "ui/timelineheader.h"
|
||||||
|
#include "ui/timelinetools.h"
|
||||||
|
#include "ui/labelslider.h"
|
||||||
|
#include "ui/graphview.h"
|
||||||
|
#include "project/effect.h"
|
||||||
|
#include "project/effectfield.h"
|
||||||
|
#include "project/effectrow.h"
|
||||||
|
#include "project/clip.h"
|
||||||
|
#include "panels.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
GraphEditor::GraphEditor(QWidget* parent) : QDockWidget(parent), row(NULL) {
|
||||||
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
setWindowTitle("Graph Editor");
|
||||||
|
resize(720, 480);
|
||||||
|
|
||||||
|
QWidget* main_widget = new QWidget();
|
||||||
|
setWidget(main_widget);
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout();
|
||||||
|
main_widget->setLayout(layout);
|
||||||
|
|
||||||
|
QWidget* tool_widget = new QWidget();
|
||||||
|
tool_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
||||||
|
QHBoxLayout* tools = new QHBoxLayout();
|
||||||
|
tool_widget->setLayout(tools);
|
||||||
|
|
||||||
|
QWidget* left_tool_widget = new QWidget();
|
||||||
|
QHBoxLayout* left_tool_layout = new QHBoxLayout();
|
||||||
|
left_tool_layout->setSpacing(0);
|
||||||
|
left_tool_layout->setMargin(0);
|
||||||
|
left_tool_widget->setLayout(left_tool_layout);
|
||||||
|
tools->addWidget(left_tool_widget);
|
||||||
|
QWidget* center_tool_widget = new QWidget();
|
||||||
|
QHBoxLayout* center_tool_layout = new QHBoxLayout();
|
||||||
|
center_tool_layout->setSpacing(0);
|
||||||
|
center_tool_layout->setMargin(0);
|
||||||
|
center_tool_widget->setLayout(center_tool_layout);
|
||||||
|
tools->addWidget(center_tool_widget);
|
||||||
|
QWidget* right_tool_widget = new QWidget();
|
||||||
|
QHBoxLayout* right_tool_layout = new QHBoxLayout();
|
||||||
|
right_tool_layout->setSpacing(0);
|
||||||
|
right_tool_layout->setMargin(0);
|
||||||
|
right_tool_widget->setLayout(right_tool_layout);
|
||||||
|
tools->addWidget(right_tool_widget);
|
||||||
|
|
||||||
|
keyframe_nav = new KeyframeNavigator();
|
||||||
|
keyframe_nav->enable_keyframes(true);
|
||||||
|
keyframe_nav->enable_keyframe_toggle(false);
|
||||||
|
left_tool_layout->addWidget(keyframe_nav);
|
||||||
|
left_tool_layout->addStretch();
|
||||||
|
|
||||||
|
linear_button = new QPushButton("Linear");
|
||||||
|
linear_button->setProperty("type", KEYFRAME_TYPE_LINEAR);
|
||||||
|
linear_button->setCheckable(true);
|
||||||
|
bezier_button = new QPushButton("Bezier");
|
||||||
|
bezier_button->setProperty("type", KEYFRAME_TYPE_BEZIER);
|
||||||
|
bezier_button->setCheckable(true);
|
||||||
|
hold_button = new QPushButton("Hold");
|
||||||
|
hold_button->setProperty("type", KEYFRAME_TYPE_HOLD);
|
||||||
|
hold_button->setCheckable(true);
|
||||||
|
|
||||||
|
center_tool_layout->addStretch();
|
||||||
|
center_tool_layout->addWidget(linear_button);
|
||||||
|
center_tool_layout->addWidget(bezier_button);
|
||||||
|
center_tool_layout->addWidget(hold_button);
|
||||||
|
|
||||||
|
layout->addWidget(tool_widget);
|
||||||
|
|
||||||
|
QWidget* central_widget = new QWidget();
|
||||||
|
QVBoxLayout* central_layout = new QVBoxLayout();
|
||||||
|
central_widget->setLayout(central_layout);
|
||||||
|
central_layout->setSpacing(0);
|
||||||
|
central_layout->setMargin(0);
|
||||||
|
header = new TimelineHeader();
|
||||||
|
header->viewer = panel_sequence_viewer;
|
||||||
|
central_layout->addWidget(header);
|
||||||
|
view = new GraphView();
|
||||||
|
central_layout->addWidget(view);
|
||||||
|
|
||||||
|
layout->addWidget(central_widget);
|
||||||
|
|
||||||
|
QWidget* value_widget = new QWidget();
|
||||||
|
value_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
||||||
|
QHBoxLayout* values = new QHBoxLayout();
|
||||||
|
value_widget->setLayout(values);
|
||||||
|
values->addStretch();
|
||||||
|
|
||||||
|
QWidget* central_value_widget = new QWidget();
|
||||||
|
value_layout = new QHBoxLayout();
|
||||||
|
value_layout->setMargin(0);
|
||||||
|
value_layout->addWidget(new QLabel("")); // a spacer so the layout doesn't jump
|
||||||
|
central_value_widget->setLayout(value_layout);
|
||||||
|
values->addWidget(central_value_widget);
|
||||||
|
|
||||||
|
values->addStretch();
|
||||||
|
layout->addWidget(value_widget);
|
||||||
|
|
||||||
|
current_row_desc = new QLabel();
|
||||||
|
current_row_desc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
||||||
|
current_row_desc->setAlignment(Qt::AlignCenter);
|
||||||
|
layout->addWidget(current_row_desc);
|
||||||
|
|
||||||
|
connect(view, SIGNAL(zoom_changed(double)), header, SLOT(update_zoom(double)));
|
||||||
|
connect(view, SIGNAL(x_scroll_changed(int)), header, SLOT(set_scroll(int)));
|
||||||
|
connect(view, SIGNAL(selection_changed(bool, int)), this, SLOT(set_key_button_enabled(bool, int)));
|
||||||
|
|
||||||
|
connect(linear_button, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_type()));
|
||||||
|
connect(bezier_button, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_type()));
|
||||||
|
connect(hold_button, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_type()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::update_panel() {
|
||||||
|
if (isVisible()) {
|
||||||
|
if (row != NULL) {
|
||||||
|
int slider_index = 0;
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
EffectField* field = row->field(i);
|
||||||
|
if (field->type == EFFECT_FIELD_DOUBLE) {
|
||||||
|
slider_proxies.at(slider_index)->set_value(row->field(i)->get_current_data().toDouble(), false);
|
||||||
|
slider_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header->update();
|
||||||
|
view->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::set_row(EffectRow *r) {
|
||||||
|
for (int i=0;i<slider_proxies.size();i++) {
|
||||||
|
delete slider_proxies.at(i);
|
||||||
|
delete slider_proxy_buttons.at(i);
|
||||||
|
}
|
||||||
|
slider_proxies.clear();
|
||||||
|
slider_proxy_buttons.clear();
|
||||||
|
slider_proxy_sources.clear();
|
||||||
|
|
||||||
|
if (row != NULL) {
|
||||||
|
// clear old row connections
|
||||||
|
disconnect(keyframe_nav, SIGNAL(goto_previous_key()), row, SLOT(goto_previous_key()));
|
||||||
|
disconnect(keyframe_nav, SIGNAL(toggle_key()), row, SLOT(toggle_key()));
|
||||||
|
disconnect(keyframe_nav, SIGNAL(goto_next_key()), row, SLOT(goto_next_key()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found_vals = false;
|
||||||
|
|
||||||
|
if (r != NULL && r->isKeyframing()) {
|
||||||
|
for (int i=0;i<r->fieldCount();i++) {
|
||||||
|
EffectField* field = r->field(i);
|
||||||
|
if (field->type == EFFECT_FIELD_DOUBLE) {
|
||||||
|
QPushButton* slider_button = new QPushButton();
|
||||||
|
slider_button->setCheckable(true);
|
||||||
|
slider_button->setChecked(true);
|
||||||
|
slider_button->setIcon(QIcon(":/icons/record.png"));
|
||||||
|
slider_button->setProperty("field", i);
|
||||||
|
slider_button->setIconSize(QSize(8, 8));
|
||||||
|
slider_button->setMaximumSize(QSize(12, 12));
|
||||||
|
connect(slider_button, SIGNAL(toggled(bool)), this, SLOT(set_field_visibility(bool)));
|
||||||
|
slider_proxy_buttons.append(slider_button);
|
||||||
|
value_layout->addWidget(slider_button);
|
||||||
|
|
||||||
|
LabelSlider* slider = new LabelSlider();
|
||||||
|
slider->set_color(get_curve_color(i, r->fieldCount()).name());
|
||||||
|
connect(slider, SIGNAL(valueChanged()), this, SLOT(passthrough_slider_value()));
|
||||||
|
slider_proxies.append(slider);
|
||||||
|
value_layout->addWidget(slider);
|
||||||
|
|
||||||
|
slider_proxy_sources.append(static_cast<LabelSlider*>(field->ui_element));
|
||||||
|
|
||||||
|
found_vals = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_vals) {
|
||||||
|
row = r;
|
||||||
|
current_row_desc->setText(row->parent_effect->parent_clip->name + " :: " + row->parent_effect->meta->name + " :: " + row->get_name());
|
||||||
|
header->set_visible_in(r->parent_effect->parent_clip->timeline_in);
|
||||||
|
|
||||||
|
connect(keyframe_nav, SIGNAL(goto_previous_key()), row, SLOT(goto_previous_key()));
|
||||||
|
connect(keyframe_nav, SIGNAL(toggle_key()), row, SLOT(toggle_key()));
|
||||||
|
connect(keyframe_nav, SIGNAL(goto_next_key()), row, SLOT(goto_next_key()));
|
||||||
|
} else {
|
||||||
|
row = NULL;
|
||||||
|
current_row_desc->setText(0);
|
||||||
|
}
|
||||||
|
view->set_row(row);
|
||||||
|
update_panel();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GraphEditor::view_is_focused() {
|
||||||
|
return view->hasFocus() || header->hasFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::delete_selected_keys() {
|
||||||
|
view->delete_selected_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::select_all() {
|
||||||
|
view->select_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::set_key_button_enabled(bool e, int type) {
|
||||||
|
linear_button->setEnabled(e);
|
||||||
|
linear_button->setChecked(type == KEYFRAME_TYPE_LINEAR);
|
||||||
|
bezier_button->setEnabled(e);
|
||||||
|
bezier_button->setChecked(type == KEYFRAME_TYPE_BEZIER);
|
||||||
|
hold_button->setEnabled(e);
|
||||||
|
hold_button->setChecked(type == KEYFRAME_TYPE_HOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::passthrough_slider_value() {
|
||||||
|
for (int i=0;i<slider_proxies.size();i++) {
|
||||||
|
if (slider_proxies.at(i) == sender()) {
|
||||||
|
slider_proxy_sources.at(i)->set_value(slider_proxies.at(i)->value(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::set_keyframe_type() {
|
||||||
|
linear_button->setChecked(linear_button == sender());
|
||||||
|
bezier_button->setChecked(bezier_button == sender());
|
||||||
|
hold_button->setChecked(hold_button == sender());
|
||||||
|
view->set_selected_keyframe_type(sender()->property("type").toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphEditor::set_field_visibility(bool b) {
|
||||||
|
view->set_field_visibility(sender()->property("field").toInt(), b);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef GRAPHEDITOR_H
|
||||||
|
#define GRAPHEDITOR_H
|
||||||
|
|
||||||
|
#include <QDockWidget>
|
||||||
|
|
||||||
|
class GraphView;
|
||||||
|
class TimelineHeader;
|
||||||
|
class QPushButton;
|
||||||
|
class EffectRow;
|
||||||
|
class QHBoxLayout;
|
||||||
|
class LabelSlider;
|
||||||
|
class QLabel;
|
||||||
|
class KeyframeNavigator;
|
||||||
|
|
||||||
|
class GraphEditor : public QDockWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
GraphEditor(QWidget* parent = 0);
|
||||||
|
void update_panel();
|
||||||
|
void set_row(EffectRow* r);
|
||||||
|
bool view_is_focused();
|
||||||
|
void delete_selected_keys();
|
||||||
|
void select_all();
|
||||||
|
private:
|
||||||
|
GraphView* view;
|
||||||
|
TimelineHeader* header;
|
||||||
|
QHBoxLayout* value_layout;
|
||||||
|
QVector<LabelSlider*> slider_proxies;
|
||||||
|
QVector<QPushButton*> slider_proxy_buttons;
|
||||||
|
QVector<LabelSlider*> slider_proxy_sources;
|
||||||
|
QLabel* current_row_desc;
|
||||||
|
EffectRow* row;
|
||||||
|
KeyframeNavigator* keyframe_nav;
|
||||||
|
QPushButton* linear_button;
|
||||||
|
QPushButton* bezier_button;
|
||||||
|
QPushButton* hold_button;
|
||||||
|
private slots:
|
||||||
|
void set_key_button_enabled(bool e, int type);
|
||||||
|
void passthrough_slider_value();
|
||||||
|
void set_keyframe_type();
|
||||||
|
void set_field_visibility(bool b);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GRAPHEDITOR_H
|
||||||
+37
-5
@@ -8,6 +8,7 @@
|
|||||||
#include "project/clip.h"
|
#include "project/clip.h"
|
||||||
#include "project/transition.h"
|
#include "project/transition.h"
|
||||||
#include "io/config.h"
|
#include "io/config.h"
|
||||||
|
#include "grapheditor.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
Project* panel_project = 0;
|
Project* panel_project = 0;
|
||||||
@@ -15,6 +16,7 @@ EffectControls* panel_effect_controls = 0;
|
|||||||
Viewer* panel_sequence_viewer = 0;
|
Viewer* panel_sequence_viewer = 0;
|
||||||
Viewer* panel_footage_viewer = 0;
|
Viewer* panel_footage_viewer = 0;
|
||||||
Timeline* panel_timeline = 0;
|
Timeline* panel_timeline = 0;
|
||||||
|
GraphEditor* panel_graph_editor = 0;
|
||||||
|
|
||||||
void update_effect_controls() {
|
void update_effect_controls() {
|
||||||
// SEND CLIPS TO EFFECT CONTROLS
|
// SEND CLIPS TO EFFECT CONTROLS
|
||||||
@@ -105,20 +107,21 @@ void update_ui(bool modified) {
|
|||||||
panel_effect_controls->update_keyframes();
|
panel_effect_controls->update_keyframes();
|
||||||
panel_timeline->repaint_timeline();
|
panel_timeline->repaint_timeline();
|
||||||
panel_sequence_viewer->update_viewer();
|
panel_sequence_viewer->update_viewer();
|
||||||
|
panel_graph_editor->update_panel();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDockWidget *get_focused_panel() {
|
QDockWidget *get_focused_panel() {
|
||||||
QDockWidget* w = NULL;
|
QDockWidget* w = NULL;
|
||||||
if (config.hover_focus) {
|
if (config.hover_focus) {
|
||||||
if (panel_project->rect().contains(panel_project->mapFromGlobal(QCursor::pos()))) {
|
if (panel_project->underMouse()) {
|
||||||
w = panel_project;
|
w = panel_project;
|
||||||
} else if (panel_effect_controls->rect().contains(panel_effect_controls->mapFromGlobal(QCursor::pos()))) {
|
} else if (panel_effect_controls->underMouse()) {
|
||||||
w = panel_effect_controls;
|
w = panel_effect_controls;
|
||||||
} else if (panel_sequence_viewer->rect().contains(panel_sequence_viewer->mapFromGlobal(QCursor::pos()))) {
|
} else if (panel_sequence_viewer->underMouse()) {
|
||||||
w = panel_sequence_viewer;
|
w = panel_sequence_viewer;
|
||||||
} else if (panel_footage_viewer->rect().contains(panel_footage_viewer->mapFromGlobal(QCursor::pos()))) {
|
} else if (panel_footage_viewer->underMouse()) {
|
||||||
w = panel_footage_viewer;
|
w = panel_footage_viewer;
|
||||||
} else if (panel_timeline->rect().contains(panel_timeline->mapFromGlobal(QCursor::pos()))) {
|
} else if (panel_timeline->underMouse()) {
|
||||||
w = panel_timeline;
|
w = panel_timeline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,3 +140,32 @@ QDockWidget *get_focused_panel() {
|
|||||||
}
|
}
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void alloc_panels(QWidget* parent) {
|
||||||
|
// TODO maybe replace these with non-pointers later on?
|
||||||
|
panel_sequence_viewer = new Viewer(parent);
|
||||||
|
panel_sequence_viewer->setObjectName("seq_viewer");
|
||||||
|
panel_footage_viewer = new Viewer(parent);
|
||||||
|
panel_footage_viewer->setObjectName("footage_viewer");
|
||||||
|
panel_project = new Project(parent);
|
||||||
|
panel_project->setObjectName("proj_root");
|
||||||
|
panel_effect_controls = new EffectControls(parent);
|
||||||
|
panel_effect_controls->setObjectName("fx_controls");
|
||||||
|
panel_timeline = new Timeline(parent);
|
||||||
|
panel_timeline->setObjectName("timeline");
|
||||||
|
panel_graph_editor = new GraphEditor(parent);
|
||||||
|
panel_graph_editor->setObjectName("graph_editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_panels() {
|
||||||
|
delete panel_sequence_viewer;
|
||||||
|
panel_sequence_viewer = NULL;
|
||||||
|
delete panel_footage_viewer;
|
||||||
|
panel_footage_viewer = NULL;
|
||||||
|
delete panel_project;
|
||||||
|
panel_project = NULL;
|
||||||
|
delete panel_effect_controls;
|
||||||
|
panel_effect_controls = NULL;
|
||||||
|
delete panel_timeline;
|
||||||
|
panel_timeline = NULL;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ class Project;
|
|||||||
class EffectControls;
|
class EffectControls;
|
||||||
class Viewer;
|
class Viewer;
|
||||||
class Timeline;
|
class Timeline;
|
||||||
|
class GraphEditor;
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
class QDockWidget;
|
class QDockWidget;
|
||||||
|
|
||||||
extern Project* panel_project;
|
extern Project* panel_project;
|
||||||
@@ -12,8 +15,11 @@ extern EffectControls* panel_effect_controls;
|
|||||||
extern Viewer* panel_sequence_viewer;
|
extern Viewer* panel_sequence_viewer;
|
||||||
extern Viewer* panel_footage_viewer;
|
extern Viewer* panel_footage_viewer;
|
||||||
extern Timeline* panel_timeline;
|
extern Timeline* panel_timeline;
|
||||||
|
extern GraphEditor* panel_graph_editor;
|
||||||
|
|
||||||
void update_ui(bool modified);
|
void update_ui(bool modified);
|
||||||
QDockWidget* get_focused_panel();
|
QDockWidget* get_focused_panel();
|
||||||
|
void alloc_panels(QWidget *parent);
|
||||||
|
void free_panels();
|
||||||
|
|
||||||
#endif // PANELS_H
|
#endif // PANELS_H
|
||||||
|
|||||||
+4
-2
@@ -60,7 +60,7 @@ QString recent_proj_file;
|
|||||||
Project::Project(QWidget *parent) :
|
Project::Project(QWidget *parent) :
|
||||||
QDockWidget(parent)
|
QDockWidget(parent)
|
||||||
{
|
{
|
||||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
QWidget* dockWidgetContents = new QWidget();
|
QWidget* dockWidgetContents = new QWidget();
|
||||||
QVBoxLayout* verticalLayout = new QVBoxLayout(dockWidgetContents);
|
QVBoxLayout* verticalLayout = new QVBoxLayout(dockWidgetContents);
|
||||||
@@ -469,12 +469,14 @@ void Project::delete_selected_media() {
|
|||||||
if (confirm_delete) {
|
if (confirm_delete) {
|
||||||
delete_clips_in_clipboard_with_media(ca, item);
|
delete_clips_in_clipboard_with_media(ca, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove
|
// remove
|
||||||
if (remove) {
|
if (remove) {
|
||||||
|
panel_effect_controls->clear_effects(true);
|
||||||
|
sequence->selections.clear();
|
||||||
|
|
||||||
// remove media and parents
|
// remove media and parents
|
||||||
for (int m=0;m<parents.size();m++) {
|
for (int m=0;m<parents.size();m++) {
|
||||||
for (int l=0;l<items.size();l++) {
|
for (int l=0;l<items.size();l++) {
|
||||||
|
|||||||
+2
-6
@@ -43,12 +43,6 @@ long refactor_frame_number(long framenumber, double source_frame_rate, double ta
|
|||||||
return qRound(((double)framenumber/source_frame_rate)*target_frame_rate);
|
return qRound(((double)framenumber/source_frame_rate)*target_frame_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_selection_rectangle(QPainter& painter, const QRect& rect) {
|
|
||||||
painter.setPen(QColor(204, 204, 204));
|
|
||||||
painter.setBrush(QColor(0, 0, 0, 32));
|
|
||||||
painter.drawRect(rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
Timeline::Timeline(QWidget *parent) :
|
Timeline::Timeline(QWidget *parent) :
|
||||||
QDockWidget(parent),
|
QDockWidget(parent),
|
||||||
cursor_frame(0),
|
cursor_frame(0),
|
||||||
@@ -80,6 +74,8 @@ Timeline::Timeline(QWidget *parent) :
|
|||||||
last_frame(0),
|
last_frame(0),
|
||||||
scroll(0)
|
scroll(0)
|
||||||
{
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
setup_ui();
|
setup_ui();
|
||||||
|
|
||||||
default_track_height = (QGuiApplication::primaryScreen()->logicalDotsPerInch() / 96) * TRACK_DEFAULT_HEIGHT;
|
default_track_height = (QGuiApplication::primaryScreen()->logicalDotsPerInch() / 96) * TRACK_DEFAULT_HEIGHT;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ struct FootageStream;
|
|||||||
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
|
long refactor_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
|
||||||
int getScreenPointFromFrame(double zoom, long frame);
|
int getScreenPointFromFrame(double zoom, long frame);
|
||||||
long getFrameFromScreenPoint(double zoom, int x);
|
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);
|
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, bool relative = false);
|
void move_clip(ComboAction *ca, Clip *c, long iin, long iout, long iclip_in, int itrack, bool verify_transitions = true, bool relative = false);
|
||||||
void ripple_clips(ComboAction *ca, Sequence* s, long point, long length, const QVector<int>& ignore = QVector<int>());
|
void ripple_clips(ComboAction *ca, Sequence* s, long point, long length, const QVector<int>& ignore = QVector<int>());
|
||||||
|
|||||||
+15
-11
@@ -46,6 +46,8 @@ Viewer::Viewer(QWidget *parent) :
|
|||||||
panel_name("Viewer: "),
|
panel_name("Viewer: "),
|
||||||
minimum_zoom(1.0)
|
minimum_zoom(1.0)
|
||||||
{
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
|
||||||
setup_ui();
|
setup_ui();
|
||||||
|
|
||||||
headers->viewer = this;
|
headers->viewer = this;
|
||||||
@@ -449,8 +451,6 @@ void Viewer::set_sb_max() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Viewer::setup_ui() {
|
void Viewer::setup_ui() {
|
||||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
|
||||||
|
|
||||||
QWidget* contents = new QWidget();
|
QWidget* contents = new QWidget();
|
||||||
|
|
||||||
QVBoxLayout* layout = new QVBoxLayout(contents);
|
QVBoxLayout* layout = new QVBoxLayout(contents);
|
||||||
@@ -573,14 +573,14 @@ void Viewer::set_media(Media* m) {
|
|||||||
seq->frame_rate = 30;
|
seq->frame_rate = 30;
|
||||||
|
|
||||||
if (footage->video_tracks.size() > 0) {
|
if (footage->video_tracks.size() > 0) {
|
||||||
const FootageStream& video_stream = footage->video_tracks.at(0);
|
const FootageStream& video_stream = footage->video_tracks.at(0);
|
||||||
seq->width = video_stream.video_width;
|
seq->width = video_stream.video_width;
|
||||||
seq->height = video_stream.video_height;
|
seq->height = video_stream.video_height;
|
||||||
if (video_stream.video_frame_rate > 0 && !video_stream.infinite_length) seq->frame_rate = video_stream.video_frame_rate;
|
if (video_stream.video_frame_rate > 0 && !video_stream.infinite_length) seq->frame_rate = video_stream.video_frame_rate;
|
||||||
|
|
||||||
Clip* c = new Clip(seq);
|
Clip* c = new Clip(seq);
|
||||||
c->media = media;
|
c->media = media;
|
||||||
c->media_stream = video_stream.file_index;
|
c->media_stream = video_stream.file_index;
|
||||||
c->timeline_in = 0;
|
c->timeline_in = 0;
|
||||||
c->timeline_out = footage->get_length_in_frames(seq->frame_rate);
|
c->timeline_out = footage->get_length_in_frames(seq->frame_rate);
|
||||||
if (c->timeline_out <= 0) c->timeline_out = 150;
|
if (c->timeline_out <= 0) c->timeline_out = 150;
|
||||||
@@ -594,12 +594,12 @@ void Viewer::set_media(Media* m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (footage->audio_tracks.size() > 0) {
|
if (footage->audio_tracks.size() > 0) {
|
||||||
const FootageStream& audio_stream = footage->audio_tracks.at(0);
|
const FootageStream& audio_stream = footage->audio_tracks.at(0);
|
||||||
seq->audio_frequency = audio_stream.audio_frequency;
|
seq->audio_frequency = audio_stream.audio_frequency;
|
||||||
|
|
||||||
Clip* c = new Clip(seq);
|
Clip* c = new Clip(seq);
|
||||||
c->media = media;
|
c->media = media;
|
||||||
c->media_stream = audio_stream.file_index;
|
c->media_stream = audio_stream.file_index;
|
||||||
c->timeline_in = 0;
|
c->timeline_in = 0;
|
||||||
c->timeline_out = footage->get_length_in_frames(seq->frame_rate);
|
c->timeline_out = footage->get_length_in_frames(seq->frame_rate);
|
||||||
c->track = 0;
|
c->track = 0;
|
||||||
@@ -610,7 +610,7 @@ void Viewer::set_media(Media* m) {
|
|||||||
if (footage->video_tracks.size() == 0) {
|
if (footage->video_tracks.size() == 0) {
|
||||||
viewer_widget->waveform = true;
|
viewer_widget->waveform = true;
|
||||||
viewer_widget->waveform_clip = c;
|
viewer_widget->waveform_clip = c;
|
||||||
viewer_widget->waveform_ms = &audio_stream;
|
viewer_widget->waveform_ms = &audio_stream;
|
||||||
viewer_widget->update();
|
viewer_widget->update();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -698,6 +698,10 @@ void Viewer::clean_created_seq() {
|
|||||||
void Viewer::set_sequence(bool main, Sequence *s) {
|
void Viewer::set_sequence(bool main, Sequence *s) {
|
||||||
reset_all_audio();
|
reset_all_audio();
|
||||||
|
|
||||||
|
if (seq != NULL) {
|
||||||
|
closeActiveClips(seq);
|
||||||
|
}
|
||||||
|
|
||||||
main_sequence = main;
|
main_sequence = main;
|
||||||
seq = (main) ? sequence : s;
|
seq = (main) ? sequence : s;
|
||||||
|
|
||||||
|
|||||||
@@ -101,8 +101,10 @@ void stop_audio() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear_audio_ibuffer() {
|
void clear_audio_ibuffer() {
|
||||||
|
if (audio_thread != NULL) audio_thread->lock.lock();
|
||||||
memset(audio_ibuffer, 0, audio_ibuffer_size);
|
memset(audio_ibuffer, 0, audio_ibuffer_size);
|
||||||
audio_ibuffer_read = 0;
|
audio_ibuffer_read = 0;
|
||||||
|
if (audio_thread != NULL) audio_thread->lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int current_audio_freq() {
|
int current_audio_freq() {
|
||||||
|
|||||||
+85
-86
@@ -37,39 +37,39 @@ bool texture_failed = false;
|
|||||||
bool rendering = false;
|
bool rendering = false;
|
||||||
|
|
||||||
bool clip_uses_cacher(Clip* clip) {
|
bool clip_uses_cacher(Clip* clip) {
|
||||||
return (clip->media == NULL && clip->track >= 0) || (clip->media != NULL && clip->media->get_type() == MEDIA_TYPE_FOOTAGE);
|
return (clip->media == NULL && clip->track >= 0) || (clip->media != NULL && clip->media->get_type() == MEDIA_TYPE_FOOTAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_clip(Clip* clip, bool multithreaded) {
|
void open_clip(Clip* clip, bool multithreaded) {
|
||||||
if (clip_uses_cacher(clip)) {
|
if (clip_uses_cacher(clip)) {
|
||||||
clip->multithreaded = multithreaded;
|
clip->multithreaded = multithreaded;
|
||||||
if (multithreaded) {
|
if (multithreaded) {
|
||||||
if (clip->open_lock.tryLock()) {
|
if (clip->open_lock.tryLock()) {
|
||||||
// maybe keep cacher instance in memory while clip exists for performance?
|
// maybe keep cacher instance in memory while clip exists for performance?
|
||||||
clip->cacher = new Cacher(clip);
|
clip->cacher = new Cacher(clip);
|
||||||
QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater()));
|
QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater()));
|
||||||
clip->cacher->start((clip->track < 0) ? QThread::NormalPriority : QThread::TimeCriticalPriority);
|
clip->cacher->start((clip->track < 0) ? QThread::NormalPriority : QThread::TimeCriticalPriority);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clip->finished_opening = false;
|
clip->finished_opening = false;
|
||||||
clip->open = true;
|
clip->open = true;
|
||||||
|
|
||||||
open_clip_worker(clip);
|
open_clip_worker(clip);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clip->open = true;
|
clip->open = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_clip(Clip* clip) {
|
void close_clip(Clip* clip, bool wait) {
|
||||||
// destroy opengl texture in main thread
|
// destroy opengl texture in main thread
|
||||||
if (clip->texture != NULL) {
|
if (clip->texture != NULL) {
|
||||||
delete clip->texture;
|
delete clip->texture;
|
||||||
clip->texture = NULL;
|
clip->texture = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0;i<clip->effects.size();i++) {
|
for (int i=0;i<clip->effects.size();i++) {
|
||||||
clip->effects.at(i)->close();
|
if (clip->effects.at(i)->is_open()) clip->effects.at(i)->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip->fbo != NULL) {
|
if (clip->fbo != NULL) {
|
||||||
@@ -79,29 +79,30 @@ void close_clip(Clip* clip) {
|
|||||||
clip->fbo = NULL;
|
clip->fbo = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clip_uses_cacher(clip)) {
|
if (clip_uses_cacher(clip)) {
|
||||||
if (clip->multithreaded) {
|
if (clip->multithreaded) {
|
||||||
clip->cacher->caching = false;
|
clip->cacher->caching = false;
|
||||||
clip->can_cache.wakeAll();
|
clip->can_cache.wakeAll();
|
||||||
} else {
|
if (wait) clip->cacher->wait();
|
||||||
close_clip_worker(clip);
|
} else {
|
||||||
}
|
close_clip_worker(clip);
|
||||||
} else {
|
}
|
||||||
if (clip->media != NULL && clip->media->get_type() == MEDIA_TYPE_SEQUENCE)
|
} else {
|
||||||
closeActiveClips(clip->media->to_sequence(), false);
|
if (clip->media != NULL && clip->media->get_type() == MEDIA_TYPE_SEQUENCE)
|
||||||
|
closeActiveClips(clip->media->to_sequence());
|
||||||
|
|
||||||
clip->open = false;
|
clip->open = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip*>& nests) {
|
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip*>& nests) {
|
||||||
if (clip_uses_cacher(clip)) {
|
if (clip_uses_cacher(clip)) {
|
||||||
if (clip->multithreaded) {
|
if (clip->multithreaded) {
|
||||||
clip->cacher->playhead = playhead;
|
clip->cacher->playhead = playhead;
|
||||||
clip->cacher->reset = reset;
|
clip->cacher->reset = reset;
|
||||||
clip->cacher->nests = nests;
|
clip->cacher->nests = nests;
|
||||||
clip->cacher->scrubbing = scrubbing;
|
clip->cacher->scrubbing = scrubbing;
|
||||||
if (reset && clip->queue.size() > 0) clip->cacher->interrupt = true;
|
if (reset && clip->queue.size() > 0) clip->cacher->interrupt = true;
|
||||||
|
|
||||||
clip->can_cache.wakeAll();
|
clip->can_cache.wakeAll();
|
||||||
} else {
|
} else {
|
||||||
@@ -111,16 +112,16 @@ void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<C
|
|||||||
}
|
}
|
||||||
|
|
||||||
double get_timecode(Clip* c, long playhead) {
|
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);
|
return ((double)(playhead-c->get_timeline_in_with_transition()+c->get_clip_in_with_transition())/(double)c->sequence->frame_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_clip_frame(Clip* c, long playhead) {
|
void get_clip_frame(Clip* c, long playhead) {
|
||||||
if (c->finished_opening) {
|
if (c->finished_opening) {
|
||||||
const FootageStream* ms = c->media->to_footage()->get_stream_from_file_index(c->track < 0, c->media_stream);
|
const FootageStream* ms = c->media->to_footage()->get_stream_from_file_index(c->track < 0, c->media_stream);
|
||||||
|
|
||||||
int64_t target_pts = qMax(static_cast<int64_t>(0), playhead_to_timestamp(c, playhead));
|
int64_t target_pts = qMax(static_cast<int64_t>(0), playhead_to_timestamp(c, playhead));
|
||||||
int64_t second_pts = qRound64(av_q2d(av_inv_q(c->stream->time_base)));
|
int64_t second_pts = qRound64(av_q2d(av_inv_q(c->stream->time_base)));
|
||||||
if (ms->video_interlacing != VIDEO_PROGRESSIVE) {
|
if (ms->video_interlacing != VIDEO_PROGRESSIVE) {
|
||||||
target_pts *= 2;
|
target_pts *= 2;
|
||||||
second_pts *= 2;
|
second_pts *= 2;
|
||||||
}
|
}
|
||||||
@@ -132,7 +133,7 @@ void get_clip_frame(Clip* c, long playhead) {
|
|||||||
|
|
||||||
c->queue_lock.lock();
|
c->queue_lock.lock();
|
||||||
if (c->queue.size() > 0) {
|
if (c->queue.size() > 0) {
|
||||||
if (ms->infinite_length) {
|
if (ms->infinite_length) {
|
||||||
target_frame = c->queue.at(0);
|
target_frame = c->queue.at(0);
|
||||||
#ifdef GCF_DEBUG
|
#ifdef GCF_DEBUG
|
||||||
dout << "GCF ==> USE PRECISE (INFINITE)";
|
dout << "GCF ==> USE PRECISE (INFINITE)";
|
||||||
@@ -192,14 +193,14 @@ void get_clip_frame(Clip* c, long playhead) {
|
|||||||
#endif
|
#endif
|
||||||
c->reached_end = false;
|
c->reached_end = false;
|
||||||
cache = false;
|
cache = false;
|
||||||
} else if (target_pts != c->last_invalid_ts && (target_pts < target_frame->pts || pts_diff > second_pts)) {
|
} else if (target_pts != c->last_invalid_ts && (target_pts < target_frame->pts || pts_diff > second_pts)) {
|
||||||
|
|
||||||
#ifdef GCF_DEBUG
|
#ifdef GCF_DEBUG
|
||||||
dout << "GCF ==> RESET" << target_pts << "(" << target_frame->pts << "-" << target_frame->pts+target_frame->pkt_duration << ")";
|
dout << "GCF ==> RESET" << target_pts << "(" << target_frame->pts << "-" << target_frame->pts+target_frame->pkt_duration << ")";
|
||||||
#endif
|
#endif
|
||||||
if (!config.fast_seeking) target_frame = NULL;
|
if (!config.fast_seeking) target_frame = NULL;
|
||||||
reset = true;
|
reset = true;
|
||||||
c->last_invalid_ts = target_pts;
|
c->last_invalid_ts = target_pts;
|
||||||
} else {
|
} else {
|
||||||
#ifdef GCF_DEBUG
|
#ifdef GCF_DEBUG
|
||||||
dout << "GCF ==> WAIT - target pts:" << target_pts << "closest frame:" << target_frame->pts;
|
dout << "GCF ==> WAIT - target pts:" << target_pts << "closest frame:" << target_frame->pts;
|
||||||
@@ -225,26 +226,26 @@ void get_clip_frame(Clip* c, long playhead) {
|
|||||||
int nb_components = av_pix_fmt_desc_get(static_cast<enum AVPixelFormat>(c->pix_fmt))->nb_components;
|
int nb_components = av_pix_fmt_desc_get(static_cast<enum AVPixelFormat>(c->pix_fmt))->nb_components;
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, target_frame->linesize[0]/nb_components);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, target_frame->linesize[0]/nb_components);
|
||||||
|
|
||||||
bool copied = false;
|
bool copied = false;
|
||||||
uint8_t* data = target_frame->data[0];
|
uint8_t* data = target_frame->data[0];
|
||||||
int frame_size;
|
int frame_size;
|
||||||
|
|
||||||
for (int i=0;i<c->effects.size();i++) {
|
for (int i=0;i<c->effects.size();i++) {
|
||||||
Effect* e = c->effects.at(i);
|
Effect* e = c->effects.at(i);
|
||||||
if (e->enable_image) {
|
if (e->enable_image) {
|
||||||
if (!copied) {
|
if (!copied) {
|
||||||
frame_size = target_frame->linesize[0]*target_frame->height;
|
frame_size = target_frame->linesize[0]*target_frame->height;
|
||||||
data = new uint8_t[frame_size];
|
data = new uint8_t[frame_size];
|
||||||
memcpy(data, target_frame->data[0], frame_size);
|
memcpy(data, target_frame->data[0], frame_size);
|
||||||
copied = true;
|
copied = true;
|
||||||
}
|
}
|
||||||
e->process_image(get_timecode(c, playhead), data, frame_size);
|
e->process_image(get_timecode(c, playhead), data, frame_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c->texture->setData(0, get_gl_pix_fmt_from_av(c->pix_fmt), QOpenGLTexture::UInt8, data);
|
c->texture->setData(0, get_gl_pix_fmt_from_av(c->pix_fmt), QOpenGLTexture::UInt8, data);
|
||||||
|
|
||||||
if (copied) delete [] data;
|
if (copied) delete [] data;
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
}
|
}
|
||||||
@@ -252,13 +253,13 @@ void get_clip_frame(Clip* c, long playhead) {
|
|||||||
c->queue_lock.unlock();
|
c->queue_lock.unlock();
|
||||||
|
|
||||||
// get more frames
|
// get more frames
|
||||||
QVector<Clip*> empty;
|
QVector<Clip*> empty;
|
||||||
if (cache) cache_clip(c, playhead, reset, false, empty);
|
if (cache) cache_clip(c, playhead, reset, false, empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long playhead_to_clip_frame(Clip* c, long playhead) {
|
long playhead_to_clip_frame(Clip* c, long playhead) {
|
||||||
return (qMax(0L, playhead - c->get_timeline_in_with_transition()) + c->get_clip_in_with_transition());
|
return (qMax(0L, playhead - c->get_timeline_in_with_transition()) + c->get_clip_in_with_transition());
|
||||||
}
|
}
|
||||||
|
|
||||||
double playhead_to_clip_seconds(Clip* c, long playhead) {
|
double playhead_to_clip_seconds(Clip* c, long playhead) {
|
||||||
@@ -278,11 +279,11 @@ int64_t playhead_to_timestamp(Clip* c, long playhead) {
|
|||||||
|
|
||||||
int retrieve_next_frame(Clip* c, AVFrame* f) {
|
int retrieve_next_frame(Clip* c, AVFrame* f) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int receive_ret;
|
int receive_ret;
|
||||||
|
|
||||||
// do we need to retrieve a new packet for a new frame?
|
// do we need to retrieve a new packet for a new frame?
|
||||||
av_frame_unref(f);
|
av_frame_unref(f);
|
||||||
while ((receive_ret = avcodec_receive_frame(c->codecCtx, f)) == AVERROR(EAGAIN)) {
|
while ((receive_ret = avcodec_receive_frame(c->codecCtx, f)) == AVERROR(EAGAIN)) {
|
||||||
int read_ret = 0;
|
int read_ret = 0;
|
||||||
do {
|
do {
|
||||||
if (c->pkt_written) {
|
if (c->pkt_written) {
|
||||||
@@ -293,15 +294,15 @@ int retrieve_next_frame(Clip* c, AVFrame* f) {
|
|||||||
if (read_ret >= 0) {
|
if (read_ret >= 0) {
|
||||||
c->pkt_written = true;
|
c->pkt_written = true;
|
||||||
}
|
}
|
||||||
} while (read_ret >= 0 && c->pkt->stream_index != c->media_stream);
|
} while (read_ret >= 0 && c->pkt->stream_index != c->media_stream);
|
||||||
|
|
||||||
if (read_ret >= 0) {
|
if (read_ret >= 0) {
|
||||||
int send_ret = avcodec_send_packet(c->codecCtx, c->pkt);
|
int send_ret = avcodec_send_packet(c->codecCtx, c->pkt);
|
||||||
if (send_ret < 0) {
|
if (send_ret < 0) {
|
||||||
dout << "[ERROR] Failed to send packet to decoder." << send_ret;
|
dout << "[ERROR] Failed to send packet to decoder." << send_ret;
|
||||||
return send_ret;
|
return send_ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (read_ret == AVERROR_EOF) {
|
if (read_ret == AVERROR_EOF) {
|
||||||
int send_ret = avcodec_send_packet(c->codecCtx, NULL);
|
int send_ret = avcodec_send_packet(c->codecCtx, NULL);
|
||||||
if (send_ret < 0) {
|
if (send_ret < 0) {
|
||||||
@@ -323,32 +324,30 @@ int retrieve_next_frame(Clip* c, AVFrame* f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_clip_active(Clip* c, long playhead) {
|
bool is_clip_active(Clip* c, long playhead) {
|
||||||
return c->enabled
|
return c->enabled
|
||||||
&& c->get_timeline_in_with_transition() < playhead + ceil(c->sequence->frame_rate*2)
|
&& c->get_timeline_in_with_transition() < playhead + ceil(c->sequence->frame_rate*2)
|
||||||
&& c->get_timeline_out_with_transition() > playhead
|
&& c->get_timeline_out_with_transition() > playhead
|
||||||
&& playhead - c->get_timeline_in_with_transition() + c->get_clip_in_with_transition() < c->getMaximumLength();
|
&& playhead - c->get_timeline_in_with_transition() + c->get_clip_in_with_transition() < c->getMaximumLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_sequence(Sequence* s) {
|
void set_sequence(Sequence* s) {
|
||||||
closeActiveClips(sequence, true);
|
|
||||||
panel_effect_controls->clear_effects(true);
|
panel_effect_controls->clear_effects(true);
|
||||||
sequence = s;
|
sequence = s;
|
||||||
panel_sequence_viewer->set_main_sequence();
|
panel_sequence_viewer->set_main_sequence();
|
||||||
panel_timeline->update_sequence();
|
panel_timeline->update_sequence();
|
||||||
panel_timeline->setFocus();
|
panel_timeline->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeActiveClips(Sequence *s, bool wait) {
|
void closeActiveClips(Sequence *s) {
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
for (int i=0;i<s->clips.size();i++) {
|
for (int i=0;i<s->clips.size();i++) {
|
||||||
Clip* c = s->clips.at(i);
|
Clip* c = s->clips.at(i);
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_SEQUENCE) {
|
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||||
closeActiveClips(c->media->to_sequence(), wait);
|
closeActiveClips(c->media->to_sequence());
|
||||||
if (c->open) close_clip(c);
|
if (c->open) close_clip(c, true);
|
||||||
} else if (clip_uses_cacher(c) && c->open) {
|
} else if (c->open) {
|
||||||
close_clip(c);
|
close_clip(c, true);
|
||||||
if (c->multithreaded && wait) c->cacher->wait();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@ extern bool rendering;
|
|||||||
bool clip_uses_cacher(Clip* clip);
|
bool clip_uses_cacher(Clip* clip);
|
||||||
void open_clip(Clip* clip, bool multithreaded);
|
void open_clip(Clip* clip, bool multithreaded);
|
||||||
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip *> &nests);
|
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip *> &nests);
|
||||||
void close_clip(Clip* clip);
|
void close_clip(Clip* clip, bool wait);
|
||||||
void cache_audio_worker(Clip* c, bool write_A);
|
void cache_audio_worker(Clip* c, bool write_A);
|
||||||
void cache_video_worker(Clip* c, long playhead);
|
void cache_video_worker(Clip* c, long playhead);
|
||||||
void handle_media(Sequence* sequence, long playhead, bool multithreaded);
|
void handle_media(Sequence* sequence, long playhead, bool multithreaded);
|
||||||
@@ -32,6 +32,6 @@ int retrieve_next_frame(Clip* c, AVFrame* f);
|
|||||||
bool is_clip_active(Clip* c, long playhead);
|
bool is_clip_active(Clip* c, long playhead);
|
||||||
void get_next_audio(Clip* c, bool mix);
|
void get_next_audio(Clip* c, bool mix);
|
||||||
void set_sequence(Sequence* s);
|
void set_sequence(Sequence* s);
|
||||||
void closeActiveClips(Sequence* s, bool wait);
|
void closeActiveClips(Sequence* s);
|
||||||
|
|
||||||
#endif // PLAYBACK_H
|
#endif // PLAYBACK_H
|
||||||
|
|||||||
+14
-19
@@ -12,6 +12,7 @@
|
|||||||
#include "project/media.h"
|
#include "project/media.h"
|
||||||
#include "io/clipboard.h"
|
#include "io/clipboard.h"
|
||||||
#include "undo.h"
|
#include "undo.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
@@ -113,9 +114,9 @@ void Clip::refresh() {
|
|||||||
Footage* m = media->to_footage();
|
Footage* m = media->to_footage();
|
||||||
|
|
||||||
if (track < 0 && m->video_tracks.size() > 0) {
|
if (track < 0 && m->video_tracks.size() > 0) {
|
||||||
media_stream = m->video_tracks.at(0).file_index;
|
media_stream = m->video_tracks.at(0).file_index;
|
||||||
} else if (track >= 0 && m->audio_tracks.size() > 0) {
|
} else if (track >= 0 && m->audio_tracks.size() > 0) {
|
||||||
media_stream = m->audio_tracks.at(0).file_index;
|
media_stream = m->audio_tracks.at(0).file_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
replaced = false;
|
replaced = false;
|
||||||
@@ -171,12 +172,7 @@ Transition* Clip::get_closing_transition() {
|
|||||||
|
|
||||||
Clip::~Clip() {
|
Clip::~Clip() {
|
||||||
if (open) {
|
if (open) {
|
||||||
close_clip(this);
|
close_clip(this, true);
|
||||||
|
|
||||||
// make sure clip has closed before clip is destroyed
|
|
||||||
if (multithreaded && media != NULL && media->get_type() == MEDIA_TYPE_FOOTAGE) {
|
|
||||||
cacher->wait();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION);
|
if (opening_transition != -1) this->sequence->hard_delete_transition(this, TA_OPENING_TRANSITION);
|
||||||
@@ -241,8 +237,8 @@ void Clip::recalculateMaxLength() {
|
|||||||
case MEDIA_TYPE_FOOTAGE:
|
case MEDIA_TYPE_FOOTAGE:
|
||||||
{
|
{
|
||||||
Footage* m = media->to_footage();
|
Footage* m = media->to_footage();
|
||||||
const FootageStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
|
const FootageStream* ms = m->get_stream_from_file_index(track < 0, media_stream);
|
||||||
if (ms != NULL && ms->infinite_length) {
|
if (ms != NULL && ms->infinite_length) {
|
||||||
calculated_length = LONG_MAX;
|
calculated_length = LONG_MAX;
|
||||||
} else {
|
} else {
|
||||||
calculated_length = m->get_length_in_frames(fr);
|
calculated_length = m->get_length_in_frames(fr);
|
||||||
@@ -269,7 +265,7 @@ int Clip::getWidth() {
|
|||||||
switch (media->get_type()) {
|
switch (media->get_type()) {
|
||||||
case MEDIA_TYPE_FOOTAGE:
|
case MEDIA_TYPE_FOOTAGE:
|
||||||
{
|
{
|
||||||
const FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
|
const FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
|
||||||
if (ms != NULL) return ms->video_width;
|
if (ms != NULL) return ms->video_width;
|
||||||
if (sequence != NULL) return sequence->width;
|
if (sequence != NULL) return sequence->width;
|
||||||
}
|
}
|
||||||
@@ -287,7 +283,7 @@ int Clip::getHeight() {
|
|||||||
switch (media->get_type()) {
|
switch (media->get_type()) {
|
||||||
case MEDIA_TYPE_FOOTAGE:
|
case MEDIA_TYPE_FOOTAGE:
|
||||||
{
|
{
|
||||||
const FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
|
const FootageStream* ms = media->to_footage()->get_stream_from_file_index(track < 0, media_stream);
|
||||||
if (ms != NULL) return ms->video_height;
|
if (ms != NULL) return ms->video_height;
|
||||||
if (sequence != NULL) return sequence->height;
|
if (sequence != NULL) return sequence->height;
|
||||||
}
|
}
|
||||||
@@ -309,17 +305,16 @@ void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_t
|
|||||||
track);
|
track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// move keyframes
|
||||||
for (int i=0;i<effects.size();i++) {
|
for (int i=0;i<effects.size();i++) {
|
||||||
Effect* e = effects.at(i);
|
Effect* e = effects.at(i);
|
||||||
for (int j=0;j<e->row_count();j++) {
|
for (int j=0;j<e->row_count();j++) {
|
||||||
EffectRow* r = e->row(j);
|
EffectRow* r = e->row(j);
|
||||||
for (int k=0;k<r->keyframe_times.size();k++) {
|
for (int l=0;l<r->fieldCount();l++) {
|
||||||
long new_pos = r->keyframe_times.at(k) * multiplier;
|
EffectField* f = r->field(l);
|
||||||
KeyframeMove* km = new KeyframeMove();
|
for (int k=0;k<f->keyframes.size();k++) {
|
||||||
km->movement = new_pos - r->keyframe_times.at(k);
|
ca->append(new SetLong(&f->keyframes[k].time, f->keyframes[k].time, f->keyframes[k].time * multiplier));
|
||||||
km->rows.append(r);
|
}
|
||||||
km->keyframes.append(k);
|
|
||||||
ca->append(km);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+234
-182
@@ -10,6 +10,7 @@
|
|||||||
#include "project/clip.h"
|
#include "project/clip.h"
|
||||||
#include "panels/timeline.h"
|
#include "panels/timeline.h"
|
||||||
#include "panels/effectcontrols.h"
|
#include "panels/effectcontrols.h"
|
||||||
|
#include "panels/grapheditor.h"
|
||||||
#include "ui/checkboxex.h"
|
#include "ui/checkboxex.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "io/path.h"
|
#include "io/path.h"
|
||||||
@@ -51,14 +52,14 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
|
|||||||
switch (em->internal) {
|
switch (em->internal) {
|
||||||
case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em);
|
case EFFECT_INTERNAL_TRANSFORM: return new TransformEffect(c, em);
|
||||||
case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em);
|
case EFFECT_INTERNAL_TEXT: return new TextEffect(c, em);
|
||||||
case EFFECT_INTERNAL_TIMECODE: return new TimecodeEffect(c, em);
|
case EFFECT_INTERNAL_TIMECODE: return new TimecodeEffect(c, em);
|
||||||
case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em);
|
case EFFECT_INTERNAL_SOLID: return new SolidEffect(c, em);
|
||||||
case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, em);
|
case EFFECT_INTERNAL_NOISE: return new AudioNoiseEffect(c, em);
|
||||||
case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em);
|
case EFFECT_INTERNAL_VOLUME: return new VolumeEffect(c, em);
|
||||||
case EFFECT_INTERNAL_PAN: return new PanEffect(c, em);
|
case EFFECT_INTERNAL_PAN: return new PanEffect(c, em);
|
||||||
case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em);
|
case EFFECT_INTERNAL_TONE: return new ToneEffect(c, em);
|
||||||
case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em);
|
case EFFECT_INTERNAL_SHAKE: return new ShakeEffect(c, em);
|
||||||
case EFFECT_INTERNAL_CORNERPIN: return new CornerPinEffect(c, em);
|
case EFFECT_INTERNAL_CORNERPIN: return new CornerPinEffect(c, em);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dout << "[ERROR] Invalid effect data";
|
dout << "[ERROR] Invalid effect data";
|
||||||
@@ -68,12 +69,12 @@ Effect* create_effect(Clip* c, const EffectMeta* em) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EffectMeta* get_internal_meta(int internal_id, int type) {
|
const EffectMeta* get_internal_meta(int internal_id, int type) {
|
||||||
for (int i=0;i<effects.size();i++) {
|
for (int i=0;i<effects.size();i++) {
|
||||||
if (effects.at(i).internal == internal_id && effects.at(i).type == type) {
|
if (effects.at(i).internal == internal_id && effects.at(i).type == type) {
|
||||||
return &effects.at(i);
|
return &effects.at(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_internal_effects() {
|
void load_internal_effects() {
|
||||||
@@ -81,85 +82,90 @@ void load_internal_effects() {
|
|||||||
|
|
||||||
// internal effects
|
// internal effects
|
||||||
em.type = EFFECT_TYPE_EFFECT;
|
em.type = EFFECT_TYPE_EFFECT;
|
||||||
em.subtype = EFFECT_TYPE_AUDIO;
|
em.subtype = EFFECT_TYPE_AUDIO;
|
||||||
|
|
||||||
em.name = "Volume";
|
em.name = "Volume";
|
||||||
em.internal = EFFECT_INTERNAL_VOLUME;
|
em.internal = EFFECT_INTERNAL_VOLUME;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Pan";
|
em.name = "Pan";
|
||||||
em.internal = EFFECT_INTERNAL_PAN;
|
em.internal = EFFECT_INTERNAL_PAN;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Tone";
|
em.name = "Tone";
|
||||||
em.internal = EFFECT_INTERNAL_TONE;
|
em.internal = EFFECT_INTERNAL_TONE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Noise";
|
em.name = "Noise";
|
||||||
em.internal = EFFECT_INTERNAL_NOISE;
|
em.internal = EFFECT_INTERNAL_NOISE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.subtype = EFFECT_TYPE_VIDEO;
|
em.subtype = EFFECT_TYPE_VIDEO;
|
||||||
|
|
||||||
em.name = "Transform";
|
em.name = "Transform";
|
||||||
em.category = "Distort";
|
em.category = "Distort";
|
||||||
em.internal = EFFECT_INTERNAL_TRANSFORM;
|
em.internal = EFFECT_INTERNAL_TRANSFORM;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Corner Pin";
|
em.name = "Corner Pin";
|
||||||
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
em.internal = EFFECT_INTERNAL_CORNERPIN;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Mask";
|
em.name = "Mask";
|
||||||
em.internal = EFFECT_INTERNAL_MASK;
|
em.internal = EFFECT_INTERNAL_MASK;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Shake";
|
em.name = "Shake";
|
||||||
em.internal = EFFECT_INTERNAL_SHAKE;
|
em.internal = EFFECT_INTERNAL_SHAKE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Text";
|
em.name = "Text";
|
||||||
em.category = "Render";
|
em.category = "Render";
|
||||||
em.internal = EFFECT_INTERNAL_TEXT;
|
em.internal = EFFECT_INTERNAL_TEXT;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Timecode";
|
em.name = "Timecode";
|
||||||
em.internal = EFFECT_INTERNAL_TIMECODE;
|
em.internal = EFFECT_INTERNAL_TIMECODE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Solid";
|
em.name = "Solid";
|
||||||
em.internal = EFFECT_INTERNAL_SOLID;
|
em.internal = EFFECT_INTERNAL_SOLID;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
// internal transitions
|
// internal transitions
|
||||||
em.type = EFFECT_TYPE_TRANSITION;
|
em.type = EFFECT_TYPE_TRANSITION;
|
||||||
em.category = "";
|
em.category = "";
|
||||||
|
|
||||||
em.name = "Cross Dissolve";
|
em.name = "Cross Dissolve";
|
||||||
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
|
em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.subtype = EFFECT_TYPE_AUDIO;
|
em.subtype = EFFECT_TYPE_AUDIO;
|
||||||
|
|
||||||
em.name = "Linear Fade";
|
em.name = "Linear Fade";
|
||||||
em.internal = TRANSITION_INTERNAL_LINEARFADE;
|
em.internal = TRANSITION_INTERNAL_LINEARFADE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Exponential Fade";
|
em.name = "Exponential Fade";
|
||||||
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
|
em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
|
|
||||||
em.name = "Logarithmic Fade";
|
em.name = "Logarithmic Fade";
|
||||||
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
|
em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE;
|
||||||
effects.append(em);
|
effects.append(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_shader_effects() {
|
QList<QString> get_effects_paths() {
|
||||||
QList<QString> effects_paths;
|
QList<QString> effects_paths;
|
||||||
effects_paths.append(get_app_dir() + "/effects");
|
effects_paths.append(get_app_dir() + "/effects");
|
||||||
effects_paths.append(get_app_dir() + "/../share/olive-editor/effects");
|
effects_paths.append(get_app_dir() + "/../share/olive-editor/effects");
|
||||||
QString env_path(qgetenv("OLIVE_EFFECTS_PATH"));
|
QString env_path(qgetenv("OLIVE_EFFECTS_PATH"));
|
||||||
if (!env_path.isEmpty()) effects_paths.append(env_path);
|
if (!env_path.isEmpty()) effects_paths.append(env_path);
|
||||||
|
return effects_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_shader_effects() {
|
||||||
|
QList<QString> effects_paths = get_effects_paths();
|
||||||
|
|
||||||
for (int h=0;h<effects_paths.size();h++) {
|
for (int h=0;h<effects_paths.size();h++) {
|
||||||
const QString& effects_path = effects_paths.at(h);
|
const QString& effects_path = effects_paths.at(h);
|
||||||
@@ -235,29 +241,29 @@ void EffectInit::run() {
|
|||||||
|
|
||||||
Effect::Effect(Clip* c, const EffectMeta *em) :
|
Effect::Effect(Clip* c, const EffectMeta *em) :
|
||||||
parent_clip(c),
|
parent_clip(c),
|
||||||
meta(em),
|
meta(em),
|
||||||
enable_shader(false),
|
enable_shader(false),
|
||||||
enable_coords(false),
|
enable_coords(false),
|
||||||
enable_superimpose(false),
|
enable_superimpose(false),
|
||||||
enable_image(false),
|
enable_image(false),
|
||||||
glslProgram(NULL),
|
glslProgram(NULL),
|
||||||
texture(NULL),
|
texture(NULL),
|
||||||
isOpen(false),
|
isOpen(false),
|
||||||
bound(false),
|
bound(false),
|
||||||
enable_always_update(false)
|
enable_always_update(false)
|
||||||
{
|
{
|
||||||
// set up base UI
|
// set up base UI
|
||||||
container = new CollapsibleWidget();
|
container = new CollapsibleWidget();
|
||||||
connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed()));
|
connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed()));
|
||||||
ui = new QWidget();
|
ui = new QWidget();
|
||||||
ui_layout = new QGridLayout();
|
ui_layout = new QGridLayout();
|
||||||
ui_layout->setSpacing(4);
|
ui_layout->setSpacing(4);
|
||||||
ui->setLayout(ui_layout);
|
ui->setLayout(ui_layout);
|
||||||
container->setContents(ui);
|
container->setContents(ui);
|
||||||
|
|
||||||
connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
|
connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
|
||||||
|
|
||||||
// set up UI from effect file
|
// set up UI from effect file
|
||||||
container->setText(em->name);
|
container->setText(em->name);
|
||||||
|
|
||||||
if (!em->filename.isEmpty()) {
|
if (!em->filename.isEmpty()) {
|
||||||
@@ -276,7 +282,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!row_name.isEmpty()) {
|
if (!row_name.isEmpty()) {
|
||||||
EffectRow* row = add_row(row_name + ":");
|
EffectRow* row = add_row(row_name);
|
||||||
while (!reader.atEnd() && !(reader.name() == "row" && reader.isEndElement())) {
|
while (!reader.atEnd() && !(reader.name() == "row" && reader.isEndElement())) {
|
||||||
reader.readNext();
|
reader.readNext();
|
||||||
if (reader.name() == "field" && reader.isStartElement()) {
|
if (reader.name() == "field" && reader.isStartElement()) {
|
||||||
@@ -310,7 +316,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) :
|
|||||||
if (id.isEmpty()) {
|
if (id.isEmpty()) {
|
||||||
dout << "[ERROR] Couldn't load field from" << em->filename << "- ID cannot be empty.";
|
dout << "[ERROR] Couldn't load field from" << em->filename << "- ID cannot be empty.";
|
||||||
} else if (type > -1) {
|
} else if (type > -1) {
|
||||||
EffectField* field = row->add_field(type, id);
|
EffectField* field = row->add_field(type, id);
|
||||||
connect(field, SIGNAL(changed()), this, SLOT(field_changed()));
|
connect(field, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EFFECT_FIELD_DOUBLE:
|
case EFFECT_FIELD_DOUBLE:
|
||||||
@@ -446,9 +452,9 @@ Effect::~Effect() {
|
|||||||
for (int i=0;i<rows.size();i++) {
|
for (int i=0;i<rows.size();i++) {
|
||||||
delete rows.at(i);
|
delete rows.at(i);
|
||||||
}
|
}
|
||||||
for (int i=0;i<gizmos.size();i++) {
|
for (int i=0;i<gizmos.size();i++) {
|
||||||
delete gizmos.at(i);
|
delete gizmos.at(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::copy_field_keyframes(Effect* e) {
|
void Effect::copy_field_keyframes(Effect* e) {
|
||||||
@@ -456,19 +462,17 @@ void Effect::copy_field_keyframes(Effect* e) {
|
|||||||
EffectRow* row = rows.at(i);
|
EffectRow* row = rows.at(i);
|
||||||
EffectRow* copy_row = e->rows.at(i);
|
EffectRow* copy_row = e->rows.at(i);
|
||||||
copy_row->setKeyframing(row->isKeyframing());
|
copy_row->setKeyframing(row->isKeyframing());
|
||||||
copy_row->keyframe_times = row->keyframe_times;
|
|
||||||
copy_row->keyframe_types = row->keyframe_types;
|
|
||||||
for (int j=0;j<row->fieldCount();j++) {
|
for (int j=0;j<row->fieldCount();j++) {
|
||||||
EffectField* field = row->field(j);
|
EffectField* field = row->field(j);
|
||||||
copy_row->field(j)->set_current_data(field->get_current_data());
|
EffectField* copy_field = copy_row->field(j);
|
||||||
copy_row->field(j)->keyframe_data = field->keyframe_data;
|
copy_field->keyframes = field->keyframes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectRow* Effect::add_row(const QString& name, bool savable) {
|
EffectRow* Effect::add_row(const QString& name, bool savable) {
|
||||||
EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size());
|
EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size());
|
||||||
rows.append(row);
|
rows.append(row);
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,52 +481,53 @@ EffectRow* Effect::row(int i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Effect::row_count() {
|
int Effect::row_count() {
|
||||||
return rows.size();
|
return rows.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectGizmo *Effect::add_gizmo(int type) {
|
EffectGizmo *Effect::add_gizmo(int type) {
|
||||||
EffectGizmo* gizmo = new EffectGizmo(type);
|
EffectGizmo* gizmo = new EffectGizmo(type);
|
||||||
gizmos.append(gizmo);
|
gizmos.append(gizmo);
|
||||||
return gizmo;
|
return gizmo;
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectGizmo *Effect::gizmo(int i) {
|
EffectGizmo *Effect::gizmo(int i) {
|
||||||
return gizmos.at(i);
|
return gizmos.at(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Effect::gizmo_count(){
|
int Effect::gizmo_count(){
|
||||||
return gizmos.size();
|
return gizmos.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::refresh() {}
|
void Effect::refresh() {}
|
||||||
|
|
||||||
void Effect::field_changed() {
|
void Effect::field_changed() {
|
||||||
panel_sequence_viewer->viewer_widget->update();
|
panel_sequence_viewer->viewer_widget->update();
|
||||||
|
panel_graph_editor->update_panel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::show_context_menu(const QPoint& pos) {
|
void Effect::show_context_menu(const QPoint& pos) {
|
||||||
if (meta->type == EFFECT_TYPE_EFFECT) {
|
if (meta->type == EFFECT_TYPE_EFFECT) {
|
||||||
QMenu menu(mainWindow);
|
QMenu menu(mainWindow);
|
||||||
|
|
||||||
int index = get_index_in_clip();
|
int index = get_index_in_clip();
|
||||||
|
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
QAction* move_up = menu.addAction("Move &Up");
|
QAction* move_up = menu.addAction("Move &Up");
|
||||||
connect(move_up, SIGNAL(triggered(bool)), this, SLOT(move_up()));
|
connect(move_up, SIGNAL(triggered(bool)), this, SLOT(move_up()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < parent_clip->effects.size() - 1) {
|
if (index < parent_clip->effects.size() - 1) {
|
||||||
QAction* move_down = menu.addAction("Move &Down");
|
QAction* move_down = menu.addAction("Move &Down");
|
||||||
connect(move_down, SIGNAL(triggered(bool)), this, SLOT(move_down()));
|
connect(move_down, SIGNAL(triggered(bool)), this, SLOT(move_down()));
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
|
|
||||||
QAction* del_action = menu.addAction("D&elete");
|
QAction* del_action = menu.addAction("D&elete");
|
||||||
connect(del_action, SIGNAL(triggered(bool)), this, SLOT(delete_self()));
|
connect(del_action, SIGNAL(triggered(bool)), this, SLOT(delete_self()));
|
||||||
|
|
||||||
menu.exec(container->title_bar->mapToGlobal(pos));
|
menu.exec(container->title_bar->mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::delete_self() {
|
void Effect::delete_self() {
|
||||||
@@ -572,24 +577,24 @@ void Effect::set_enabled(bool b) {
|
|||||||
|
|
||||||
QVariant load_data_from_string(int type, const QString& string) {
|
QVariant load_data_from_string(int type, const QString& string) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EFFECT_FIELD_DOUBLE: return string.toDouble();
|
case EFFECT_FIELD_DOUBLE: return string.toDouble();
|
||||||
case EFFECT_FIELD_COLOR: return QColor(string);
|
case EFFECT_FIELD_COLOR: return QColor(string);
|
||||||
case EFFECT_FIELD_STRING: return string;
|
case EFFECT_FIELD_STRING: return string;
|
||||||
case EFFECT_FIELD_BOOL: return (string == "1");
|
case EFFECT_FIELD_BOOL: return (string == "1");
|
||||||
case EFFECT_FIELD_COMBO: return string.toInt();
|
case EFFECT_FIELD_COMBO: return string.toInt();
|
||||||
case EFFECT_FIELD_FONT: return string;
|
case EFFECT_FIELD_FONT: return string;
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString save_data_to_string(int type, const QVariant& data) {
|
QString save_data_to_string(int type, const QVariant& data) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble());
|
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble());
|
||||||
case EFFECT_FIELD_COLOR: return data.value<QColor>().name();
|
case EFFECT_FIELD_COLOR: return data.value<QColor>().name();
|
||||||
case EFFECT_FIELD_STRING: return data.toString();
|
case EFFECT_FIELD_STRING: return data.toString();
|
||||||
case EFFECT_FIELD_BOOL: return QString::number(data.toBool());
|
case EFFECT_FIELD_BOOL: return QString::number(data.toBool());
|
||||||
case EFFECT_FIELD_COMBO: return QString::number(data.toInt());
|
case EFFECT_FIELD_COMBO: return QString::number(data.toInt());
|
||||||
case EFFECT_FIELD_FONT: return data.toString();
|
case EFFECT_FIELD_FONT: return data.toString();
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@@ -610,7 +615,7 @@ void Effect::load(QXmlStreamReader& stream) {
|
|||||||
stream.readNext();
|
stream.readNext();
|
||||||
|
|
||||||
// read keyframes
|
// read keyframes
|
||||||
if (stream.name() == "keyframes" && stream.isStartElement()) {
|
/*if (stream.name() == "keyframes" && stream.isStartElement()) {
|
||||||
for (int k=0;k<stream.attributes().size();k++) {
|
for (int k=0;k<stream.attributes().size();k++) {
|
||||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||||
if (attr.name() == "enabled") {
|
if (attr.name() == "enabled") {
|
||||||
@@ -631,14 +636,19 @@ void Effect::load(QXmlStreamReader& stream) {
|
|||||||
keyframe_type = attr.value().toInt();
|
keyframe_type = attr.value().toInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
row->keyframe_times.append(keyframe_frame);
|
for (int k=0;k<row->fieldCount();k++) {
|
||||||
row->keyframe_types.append(keyframe_type);
|
EffectField* field = row->field(k);
|
||||||
|
EffectKeyframe key;
|
||||||
|
key.time = keyframe_frame;
|
||||||
|
key.type = keyframe_type;
|
||||||
|
field->keyframes.append(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stream.readNext();
|
stream.readNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream.readNext();
|
stream.readNext();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// read field
|
// read field
|
||||||
if (stream.name() == "field" && stream.isStartElement()) {
|
if (stream.name() == "field" && stream.isStartElement()) {
|
||||||
@@ -678,10 +688,30 @@ void Effect::load(QXmlStreamReader& stream) {
|
|||||||
while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) {
|
while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) {
|
||||||
stream.readNext();
|
stream.readNext();
|
||||||
|
|
||||||
// read all keyframes
|
// read keyframes
|
||||||
if (stream.name() == "key" && stream.isStartElement()) {
|
if (stream.name() == "key" && stream.isStartElement()) {
|
||||||
stream.readNext();
|
row->setKeyframing(true);
|
||||||
field->keyframe_data.append(load_data_from_string(field->type, stream.text().toString()));
|
|
||||||
|
EffectKeyframe key;
|
||||||
|
for (int k=0;k<stream.attributes().size();k++) {
|
||||||
|
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||||
|
if (attr.name() == "value") {
|
||||||
|
key.data = load_data_from_string(field->type, attr.value().toString());
|
||||||
|
} else if (attr.name() == "frame") {
|
||||||
|
key.time = attr.value().toLong();
|
||||||
|
} else if (attr.name() == "type") {
|
||||||
|
key.type = attr.value().toInt();
|
||||||
|
} else if (attr.name() == "prehx") {
|
||||||
|
key.pre_handle_x = attr.value().toDouble();
|
||||||
|
} else if (attr.name() == "prehy") {
|
||||||
|
key.pre_handle_y = attr.value().toDouble();
|
||||||
|
} else if (attr.name() == "posthx") {
|
||||||
|
key.post_handle_x = attr.value().toDouble();
|
||||||
|
} else if (attr.name() == "posthy") {
|
||||||
|
key.post_handle_y = attr.value().toDouble();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
field->keyframes.append(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -701,33 +731,54 @@ void Effect::load(QXmlStreamReader& stream) {
|
|||||||
|
|
||||||
void Effect::save(QXmlStreamWriter& stream) {
|
void Effect::save(QXmlStreamWriter& stream) {
|
||||||
stream.writeAttribute("name", meta->name);
|
stream.writeAttribute("name", meta->name);
|
||||||
stream.writeAttribute("enabled", QString::number(is_enabled()));
|
stream.writeAttribute("enabled", QString::number(is_enabled()));
|
||||||
|
|
||||||
for (int i=0;i<rows.size();i++) {
|
for (int i=0;i<rows.size();i++) {
|
||||||
EffectRow* row = rows.at(i);
|
EffectRow* row = rows.at(i);
|
||||||
if (row->savable) {
|
if (row->savable) {
|
||||||
stream.writeStartElement("row"); // row
|
stream.writeStartElement("row"); // row
|
||||||
stream.writeStartElement("keyframes"); // keyframes
|
for (int j=0;j<row->fieldCount();j++) {
|
||||||
stream.writeAttribute("enabled", QString::number(row->isKeyframing()));
|
EffectField* field = row->field(j);
|
||||||
for (int j=0;j<row->keyframe_times.size();j++) {
|
stream.writeStartElement("field"); // field
|
||||||
stream.writeStartElement("key"); // key
|
stream.writeAttribute("id", field->id);
|
||||||
stream.writeAttribute("frame", QString::number(row->keyframe_times.at(j)));
|
stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data()));
|
||||||
stream.writeAttribute("type", QString::number(row->keyframe_types.at(j)));
|
for (int k=0;k<field->keyframes.size();k++) {
|
||||||
stream.writeEndElement(); // key
|
const EffectKeyframe& key = field->keyframes.at(k);
|
||||||
}
|
stream.writeStartElement("key");
|
||||||
stream.writeEndElement(); // keyframes
|
stream.writeAttribute("value", save_data_to_string(field->type, key.data));
|
||||||
for (int j=0;j<row->fieldCount();j++) {
|
stream.writeAttribute("frame", QString::number(key.time));
|
||||||
EffectField* field = row->field(j);
|
stream.writeAttribute("type", QString::number(key.type));
|
||||||
stream.writeStartElement("field"); // field
|
stream.writeAttribute("prehx", QString::number(key.pre_handle_x));
|
||||||
stream.writeAttribute("id", field->id);
|
stream.writeAttribute("prehy", QString::number(key.pre_handle_y));
|
||||||
stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data()));
|
stream.writeAttribute("posthx", QString::number(key.post_handle_x));
|
||||||
for (int k=0;k<field->keyframe_data.size();k++) {
|
stream.writeAttribute("posthy", QString::number(key.post_handle_y));
|
||||||
stream.writeTextElement("key", save_data_to_string(field->type, field->keyframe_data.at(k)));
|
stream.writeEndElement(); // key
|
||||||
}
|
}
|
||||||
stream.writeEndElement(); // field
|
stream.writeEndElement(); // field
|
||||||
}
|
}
|
||||||
stream.writeEndElement(); // row
|
stream.writeEndElement(); // row
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Effect::is_open() {
|
||||||
|
return isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Effect::validate_meta_path() {
|
||||||
|
if (!meta->path.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return;
|
||||||
|
QList<QString> effects_paths = get_effects_paths();
|
||||||
|
const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath;
|
||||||
|
for (int i=0;i<effects_paths.size();i++) {
|
||||||
|
if (QFileInfo::exists(effects_paths.at(i) + "/" + test_fn)) {
|
||||||
|
for (int j=0;j<effects.size();j++) {
|
||||||
|
if (&effects.at(j) == meta) {
|
||||||
|
effects[j].path = effects_paths.at(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,6 +792,7 @@ void Effect::open() {
|
|||||||
dout << "[WARNING] No current context to create a shader program for - will retry next repaint";
|
dout << "[WARNING] No current context to create a shader program for - will retry next repaint";
|
||||||
} else {
|
} else {
|
||||||
glslProgram = new QOpenGLShaderProgram();
|
glslProgram = new QOpenGLShaderProgram();
|
||||||
|
validate_meta_path();
|
||||||
if (!vertPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath);
|
if (!vertPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath);
|
||||||
if (!fragPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath);
|
if (!fragPath.isEmpty()) glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath);
|
||||||
glslProgram->link();
|
glslProgram->link();
|
||||||
@@ -777,16 +829,16 @@ void Effect::startEffect() {
|
|||||||
|
|
||||||
void Effect::endEffect() {
|
void Effect::endEffect() {
|
||||||
if (bound) glslProgram->release();
|
if (bound) glslProgram->release();
|
||||||
bound = false;
|
bound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::process_image(double, uint8_t *, int) {}
|
void Effect::process_image(double, uint8_t *, int) {}
|
||||||
|
|
||||||
Effect* Effect::copy(Clip* c) {
|
Effect* Effect::copy(Clip* c) {
|
||||||
Effect* copy = create_effect(c, meta);
|
Effect* copy = create_effect(c, meta);
|
||||||
copy->set_enabled(is_enabled());
|
copy->set_enabled(is_enabled());
|
||||||
copy_field_keyframes(copy);
|
copy_field_keyframes(copy);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::process_shader(double timecode, GLTextureCoords&) {
|
void Effect::process_shader(double timecode, GLTextureCoords&) {
|
||||||
@@ -831,7 +883,7 @@ GLuint Effect::process_superimpose(double timecode) {
|
|||||||
recreate_texture = true;
|
recreate_texture = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valueHasChanged(timecode) || recreate_texture || enable_always_update) {
|
if (valueHasChanged(timecode) || recreate_texture || enable_always_update) {
|
||||||
redraw(timecode);
|
redraw(timecode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,78 +904,78 @@ GLuint Effect::process_superimpose(double timecode) {
|
|||||||
void Effect::process_audio(double, double, quint8*, int, int) {
|
void Effect::process_audio(double, double, quint8*, int, int) {
|
||||||
// only volume/pan, hand off to AU and VST for all other cases
|
// only volume/pan, hand off to AU and VST for all other cases
|
||||||
|
|
||||||
/*double interval = (timecode_end-timecode_start)/nb_bytes;
|
/*double interval = (timecode_end-timecode_start)/nb_bytes;
|
||||||
|
|
||||||
for (int i=0;i<nb_bytes;i+=2) {
|
for (int i=0;i<nb_bytes;i+=2) {
|
||||||
qint32 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
|
qint32 samp = (qint16) (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF));
|
||||||
|
|
||||||
jsEngine.globalObject().setProperty("sample", samp);
|
jsEngine.globalObject().setProperty("sample", samp);
|
||||||
jsEngine.globalObject().setProperty("volume", row(0)->field(0)->get_double_value(timecode_start+(interval*i), true));
|
jsEngine.globalObject().setProperty("volume", row(0)->field(0)->get_double_value(timecode_start+(interval*i), true));
|
||||||
QJSValue result = eval.call();
|
QJSValue result = eval.call();
|
||||||
samp = result.toInt();
|
samp = result.toInt();
|
||||||
QJSValueList args;
|
QJSValueList args;
|
||||||
args << samples << nb_bytes;
|
args << samples << nb_bytes;
|
||||||
|
|
||||||
|
|
||||||
samples[i+1] = (quint8) (samp >> 8);
|
samples[i+1] = (quint8) (samp >> 8);
|
||||||
samples[i] = (quint8) samp;
|
samples[i] = (quint8) samp;
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::gizmo_draw(double, GLTextureCoords &) {}
|
void Effect::gizmo_draw(double, GLTextureCoords &) {}
|
||||||
|
|
||||||
void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) {
|
void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) {
|
||||||
for (int i=0;i<gizmos.size();i++) {
|
for (int i=0;i<gizmos.size();i++) {
|
||||||
if (gizmos.at(i) == gizmo) {
|
if (gizmos.at(i) == gizmo) {
|
||||||
ComboAction* ca = NULL;
|
ComboAction* ca = NULL;
|
||||||
if (done) ca = new ComboAction();
|
if (done) ca = new ComboAction();
|
||||||
if (gizmo->x_field1 != NULL) {
|
if (gizmo->x_field1 != NULL) {
|
||||||
gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1);
|
gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1);
|
||||||
gizmo->x_field1->make_key_from_change(ca);
|
gizmo->x_field1->make_key_from_change(ca);
|
||||||
}
|
}
|
||||||
if (gizmo->y_field1 != NULL) {
|
if (gizmo->y_field1 != NULL) {
|
||||||
gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1);
|
gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1);
|
||||||
gizmo->y_field1->make_key_from_change(ca);
|
gizmo->y_field1->make_key_from_change(ca);
|
||||||
}
|
}
|
||||||
if (gizmo->x_field2 != NULL) {
|
if (gizmo->x_field2 != NULL) {
|
||||||
gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2);
|
gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2);
|
||||||
gizmo->x_field2->make_key_from_change(ca);
|
gizmo->x_field2->make_key_from_change(ca);
|
||||||
}
|
}
|
||||||
if (gizmo->y_field2 != NULL) {
|
if (gizmo->y_field2 != NULL) {
|
||||||
gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2);
|
gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2);
|
||||||
gizmo->y_field2->make_key_from_change(ca);
|
gizmo->y_field2->make_key_from_change(ca);
|
||||||
}
|
}
|
||||||
if (done) undo_stack.push(ca);
|
if (done) undo_stack.push(ca);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::gizmo_world_to_screen() {
|
void Effect::gizmo_world_to_screen() {
|
||||||
GLfloat view_val[16];
|
GLfloat view_val[16];
|
||||||
GLfloat projection_val[16];
|
GLfloat projection_val[16];
|
||||||
glGetFloatv(GL_MODELVIEW_MATRIX, view_val);
|
glGetFloatv(GL_MODELVIEW_MATRIX, view_val);
|
||||||
glGetFloatv(GL_PROJECTION_MATRIX, projection_val);
|
glGetFloatv(GL_PROJECTION_MATRIX, projection_val);
|
||||||
|
|
||||||
QMatrix4x4 view_matrix(view_val);
|
QMatrix4x4 view_matrix(view_val);
|
||||||
QMatrix4x4 projection_matrix(projection_val);
|
QMatrix4x4 projection_matrix(projection_val);
|
||||||
|
|
||||||
for (int i=0;i<gizmos.size();i++) {
|
for (int i=0;i<gizmos.size();i++) {
|
||||||
EffectGizmo* g = gizmos.at(i);
|
EffectGizmo* g = gizmos.at(i);
|
||||||
|
|
||||||
for (int j=0;j<g->get_point_count();j++) {
|
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);
|
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_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width);
|
||||||
int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height);
|
int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height);
|
||||||
|
|
||||||
g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1);
|
g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Effect::are_gizmos_enabled() {
|
bool Effect::are_gizmos_enabled() {
|
||||||
return (gizmos.size() > 0);
|
return (gizmos.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect::redraw(double) {
|
void Effect::redraw(double) {
|
||||||
|
|||||||
+45
-44
@@ -23,16 +23,15 @@ class QXmlStreamWriter;
|
|||||||
class Effect;
|
class Effect;
|
||||||
class EffectRow;
|
class EffectRow;
|
||||||
class CheckboxEx;
|
class CheckboxEx;
|
||||||
class KeyframeDelete;
|
|
||||||
|
|
||||||
struct EffectMeta {
|
struct EffectMeta {
|
||||||
QString name;
|
QString name;
|
||||||
QString category;
|
QString category;
|
||||||
QString filename;
|
QString filename;
|
||||||
QString path;
|
QString path;
|
||||||
int internal;
|
int internal;
|
||||||
int type;
|
int type;
|
||||||
int subtype;
|
int subtype;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern QVector<EffectMeta> effects;
|
extern QVector<EffectMeta> effects;
|
||||||
@@ -70,37 +69,37 @@ extern QMutex effects_loaded;
|
|||||||
#define EFFECT_INTERNAL_COUNT 13
|
#define EFFECT_INTERNAL_COUNT 13
|
||||||
|
|
||||||
#define KEYFRAME_TYPE_LINEAR 0
|
#define KEYFRAME_TYPE_LINEAR 0
|
||||||
#define KEYFRAME_TYPE_SMOOTH 1
|
#define KEYFRAME_TYPE_BEZIER 1
|
||||||
#define KEYFRAME_TYPE_BEZIER 2
|
#define KEYFRAME_TYPE_HOLD 2
|
||||||
|
|
||||||
struct GLTextureCoords {
|
struct GLTextureCoords {
|
||||||
int grid_size;
|
int grid_size;
|
||||||
|
|
||||||
int vertexTopLeftX;
|
int vertexTopLeftX;
|
||||||
int vertexTopLeftY;
|
int vertexTopLeftY;
|
||||||
int vertexTopLeftZ;
|
int vertexTopLeftZ;
|
||||||
int vertexTopRightX;
|
int vertexTopRightX;
|
||||||
int vertexTopRightY;
|
int vertexTopRightY;
|
||||||
int vertexTopRightZ;
|
int vertexTopRightZ;
|
||||||
int vertexBottomLeftX;
|
int vertexBottomLeftX;
|
||||||
int vertexBottomLeftY;
|
int vertexBottomLeftY;
|
||||||
int vertexBottomLeftZ;
|
int vertexBottomLeftZ;
|
||||||
int vertexBottomRightX;
|
int vertexBottomRightX;
|
||||||
int vertexBottomRightY;
|
int vertexBottomRightY;
|
||||||
int vertexBottomRightZ;
|
int vertexBottomRightZ;
|
||||||
|
|
||||||
float textureTopLeftX;
|
float textureTopLeftX;
|
||||||
float textureTopLeftY;
|
float textureTopLeftY;
|
||||||
float textureTopLeftQ;
|
float textureTopLeftQ;
|
||||||
float textureTopRightX;
|
float textureTopRightX;
|
||||||
float textureTopRightY;
|
float textureTopRightY;
|
||||||
float textureTopRightQ;
|
float textureTopRightQ;
|
||||||
float textureBottomRightX;
|
float textureBottomRightX;
|
||||||
float textureBottomRightY;
|
float textureBottomRightY;
|
||||||
float textureBottomRightQ;
|
float textureBottomRightQ;
|
||||||
float textureBottomLeftX;
|
float textureBottomLeftX;
|
||||||
float textureBottomLeftY;
|
float textureBottomLeftY;
|
||||||
float textureBottomLeftQ;
|
float textureBottomLeftQ;
|
||||||
};
|
};
|
||||||
|
|
||||||
qint16 mix_audio_sample(qint16 a, qint16 b);
|
qint16 mix_audio_sample(qint16 a, qint16 b);
|
||||||
@@ -114,21 +113,21 @@ class Effect : public QObject {
|
|||||||
public:
|
public:
|
||||||
Effect(Clip* c, const EffectMeta* em);
|
Effect(Clip* c, const EffectMeta* em);
|
||||||
~Effect();
|
~Effect();
|
||||||
Clip* parent_clip;
|
Clip* parent_clip;
|
||||||
const EffectMeta* meta;
|
const EffectMeta* meta;
|
||||||
int id;
|
int id;
|
||||||
QString name;
|
QString name;
|
||||||
CollapsibleWidget* container;
|
CollapsibleWidget* container;
|
||||||
|
|
||||||
EffectRow* add_row(const QString &name, bool savable = true);
|
EffectRow* add_row(const QString &name, bool savable = true);
|
||||||
EffectRow* row(int i);
|
EffectRow* row(int i);
|
||||||
int row_count();
|
int row_count();
|
||||||
|
|
||||||
EffectGizmo* add_gizmo(int type);
|
EffectGizmo* add_gizmo(int type);
|
||||||
EffectGizmo* gizmo(int i);
|
EffectGizmo* gizmo(int i);
|
||||||
int gizmo_count();
|
int gizmo_count();
|
||||||
|
|
||||||
bool is_enabled();
|
bool is_enabled();
|
||||||
void set_enabled(bool b);
|
void set_enabled(bool b);
|
||||||
|
|
||||||
virtual void refresh();
|
virtual void refresh();
|
||||||
@@ -137,9 +136,10 @@ public:
|
|||||||
void copy_field_keyframes(Effect *e);
|
void copy_field_keyframes(Effect *e);
|
||||||
|
|
||||||
void load(QXmlStreamReader& stream);
|
void load(QXmlStreamReader& stream);
|
||||||
void save(QXmlStreamWriter& stream);
|
void save(QXmlStreamWriter& stream);
|
||||||
|
|
||||||
// glsl handling
|
// glsl handling
|
||||||
|
bool is_open();
|
||||||
void open();
|
void open();
|
||||||
void close();
|
void close();
|
||||||
virtual void startEffect();
|
virtual void startEffect();
|
||||||
@@ -147,24 +147,24 @@ public:
|
|||||||
|
|
||||||
bool enable_shader;
|
bool enable_shader;
|
||||||
bool enable_coords;
|
bool enable_coords;
|
||||||
bool enable_superimpose;
|
bool enable_superimpose;
|
||||||
bool enable_image;
|
bool enable_image;
|
||||||
|
|
||||||
int getIterations();
|
int getIterations();
|
||||||
void setIterations(int i);
|
void setIterations(int i);
|
||||||
|
|
||||||
const char* ffmpeg_filter;
|
const char* ffmpeg_filter;
|
||||||
|
|
||||||
virtual void process_image(double timecode, uint8_t* data, int size);
|
virtual void process_image(double timecode, uint8_t* data, int size);
|
||||||
virtual void process_shader(double timecode, GLTextureCoords&);
|
virtual void process_shader(double timecode, GLTextureCoords&);
|
||||||
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
|
virtual void process_coords(double timecode, GLTextureCoords& coords, int data);
|
||||||
virtual GLuint process_superimpose(double timecode);
|
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 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_draw(double timecode, GLTextureCoords& coords);
|
||||||
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done);
|
void gizmo_move(EffectGizmo* sender, int x_movement, int y_movement, double timecode, bool done);
|
||||||
void gizmo_world_to_screen();
|
void gizmo_world_to_screen();
|
||||||
bool are_gizmos_enabled();
|
bool are_gizmos_enabled();
|
||||||
public slots:
|
public slots:
|
||||||
void field_changed();
|
void field_changed();
|
||||||
private slots:
|
private slots:
|
||||||
@@ -182,17 +182,17 @@ protected:
|
|||||||
QImage img;
|
QImage img;
|
||||||
QOpenGLTexture* texture;
|
QOpenGLTexture* texture;
|
||||||
|
|
||||||
// enable effect to update constantly
|
// enable effect to update constantly
|
||||||
bool enable_always_update;
|
bool enable_always_update;
|
||||||
private:
|
private:
|
||||||
// superimpose effect
|
// superimpose effect
|
||||||
QString script;
|
QString script;
|
||||||
|
|
||||||
bool isOpen;
|
bool isOpen;
|
||||||
QVector<EffectRow*> rows;
|
QVector<EffectRow*> rows;
|
||||||
QVector<EffectGizmo*> gizmos;
|
QVector<EffectGizmo*> gizmos;
|
||||||
QGridLayout* ui_layout;
|
QGridLayout* ui_layout;
|
||||||
QWidget* ui;
|
QWidget* ui;
|
||||||
bool bound;
|
bool bound;
|
||||||
|
|
||||||
// superimpose functions
|
// superimpose functions
|
||||||
@@ -201,6 +201,7 @@ private:
|
|||||||
QVector<QVariant> cachedValues;
|
QVector<QVariant> cachedValues;
|
||||||
void delete_texture();
|
void delete_texture();
|
||||||
int get_index_in_clip();
|
int get_index_in_clip();
|
||||||
|
void validate_meta_path();
|
||||||
};
|
};
|
||||||
|
|
||||||
class EffectInit : public QThread {
|
class EffectInit : public QThread {
|
||||||
|
|||||||
+262
-243
@@ -15,347 +15,366 @@
|
|||||||
#include "project/sequence.h"
|
#include "project/sequence.h"
|
||||||
|
|
||||||
#include "io/math.h"
|
#include "io/math.h"
|
||||||
#include <QtMath>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
EffectField::EffectField(EffectRow *parent, int t, const QString &i) :
|
EffectField::EffectField(EffectRow *parent, int t, const QString &i) :
|
||||||
parent_row(parent),
|
parent_row(parent),
|
||||||
type(t),
|
type(t),
|
||||||
id(i)
|
id(i)
|
||||||
{
|
{
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case EFFECT_FIELD_DOUBLE:
|
case EFFECT_FIELD_DOUBLE:
|
||||||
{
|
{
|
||||||
LabelSlider* ls = new LabelSlider();
|
LabelSlider* ls = new LabelSlider();
|
||||||
ui_element = ls;
|
ui_element = ls;
|
||||||
connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change()));
|
connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change()));
|
||||||
}
|
connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked()));
|
||||||
break;
|
}
|
||||||
case EFFECT_FIELD_COLOR:
|
break;
|
||||||
{
|
case EFFECT_FIELD_COLOR:
|
||||||
ColorButton* cb = new ColorButton();
|
{
|
||||||
ui_element = cb;
|
ColorButton* cb = new ColorButton();
|
||||||
connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change()));
|
ui_element = cb;
|
||||||
}
|
connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change()));
|
||||||
break;
|
}
|
||||||
case EFFECT_FIELD_STRING:
|
break;
|
||||||
{
|
case EFFECT_FIELD_STRING:
|
||||||
TextEditEx* edit = new TextEditEx();
|
{
|
||||||
edit->setUndoRedoEnabled(true);
|
TextEditEx* edit = new TextEditEx();
|
||||||
ui_element = edit;
|
edit->setUndoRedoEnabled(true);
|
||||||
connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change()));
|
ui_element = edit;
|
||||||
}
|
connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change()));
|
||||||
break;
|
}
|
||||||
case EFFECT_FIELD_BOOL:
|
break;
|
||||||
{
|
case EFFECT_FIELD_BOOL:
|
||||||
CheckboxEx* cb = new CheckboxEx();
|
{
|
||||||
ui_element = cb;
|
CheckboxEx* cb = new CheckboxEx();
|
||||||
connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change()));
|
ui_element = cb;
|
||||||
connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
|
connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change()));
|
||||||
}
|
connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool)));
|
||||||
break;
|
}
|
||||||
case EFFECT_FIELD_COMBO:
|
break;
|
||||||
{
|
case EFFECT_FIELD_COMBO:
|
||||||
ComboBoxEx* cb = new ComboBoxEx();
|
{
|
||||||
ui_element = cb;
|
ComboBoxEx* cb = new ComboBoxEx();
|
||||||
connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
|
ui_element = cb;
|
||||||
}
|
connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
|
||||||
break;
|
}
|
||||||
case EFFECT_FIELD_FONT:
|
break;
|
||||||
{
|
case EFFECT_FIELD_FONT:
|
||||||
FontCombobox* fcb = new FontCombobox();
|
{
|
||||||
ui_element = fcb;
|
FontCombobox* fcb = new FontCombobox();
|
||||||
connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
|
ui_element = fcb;
|
||||||
}
|
connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change()));
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant EffectField::get_previous_data() {
|
QVariant EffectField::get_previous_data() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->getPreviousValue();
|
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->getPreviousValue();
|
||||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue();
|
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->getPreviousValue();
|
||||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue();
|
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPreviousValue();
|
||||||
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked();
|
case EFFECT_FIELD_BOOL: return !static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex();
|
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->getPreviousIndex();
|
||||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue();
|
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->getPreviousValue();
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant EffectField::get_current_data() {
|
QVariant EffectField::get_current_data() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value();
|
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->value();
|
||||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color();
|
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->get_color();
|
||||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
|
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
|
||||||
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked();
|
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
|
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
|
||||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText();
|
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->currentText();
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
double EffectField::frameToTimecode(long frame) {
|
double EffectField::frameToTimecode(long frame) {
|
||||||
return ((double) frame / parent_row->parent_effect->parent_clip->sequence->frame_rate);
|
return ((double) frame / parent_row->parent_effect->parent_clip->sequence->frame_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
long EffectField::timecodeToFrame(double timecode) {
|
long EffectField::timecodeToFrame(double timecode) {
|
||||||
return qRound(timecode * parent_row->parent_effect->parent_clip->sequence->frame_rate);
|
return qRound(timecode * parent_row->parent_effect->parent_clip->sequence->frame_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_current_data(const QVariant& data) {
|
void EffectField::set_current_data(const QVariant& data) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->set_value(data.toDouble(), false);
|
case EFFECT_FIELD_DOUBLE: return static_cast<LabelSlider*>(ui_element)->set_value(data.toDouble(), false);
|
||||||
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>());
|
case EFFECT_FIELD_COLOR: return static_cast<ColorButton*>(ui_element)->set_color(data.value<QColor>());
|
||||||
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString());
|
case EFFECT_FIELD_STRING: return static_cast<TextEditEx*>(ui_element)->setPlainTextEx(data.toString());
|
||||||
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool());
|
case EFFECT_FIELD_BOOL: return static_cast<QCheckBox*>(ui_element)->setChecked(data.toBool());
|
||||||
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt());
|
case EFFECT_FIELD_COMBO: return static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(data.toInt());
|
||||||
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(data.toString());
|
case EFFECT_FIELD_FONT: return static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(data.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) {
|
void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) {
|
||||||
int before_keyframe_index = -1;
|
int before_keyframe_index = -1;
|
||||||
int after_keyframe_index = -1;
|
int after_keyframe_index = -1;
|
||||||
long before_keyframe_time = LONG_MIN;
|
long before_keyframe_time = LONG_MIN;
|
||||||
long after_keyframe_time = LONG_MAX;
|
long after_keyframe_time = LONG_MAX;
|
||||||
long frame = timecodeToFrame(timecode);
|
long frame = timecodeToFrame(timecode);
|
||||||
|
|
||||||
for (int i=0;i<parent_row->keyframe_times.size();i++) {
|
for (int i=0;i<keyframes.size();i++) {
|
||||||
long eval_keyframe_time = parent_row->keyframe_times.at(i);
|
long eval_keyframe_time = keyframes.at(i).time;
|
||||||
if (eval_keyframe_time == frame) {
|
if (eval_keyframe_time == frame) {
|
||||||
before = i;
|
before = i;
|
||||||
after = i;
|
after = i;
|
||||||
return;
|
return;
|
||||||
} else if (eval_keyframe_time < frame && eval_keyframe_time > before_keyframe_time) {
|
} else if (eval_keyframe_time < frame && eval_keyframe_time > before_keyframe_time) {
|
||||||
before_keyframe_index = i;
|
before_keyframe_index = i;
|
||||||
before_keyframe_time = eval_keyframe_time;
|
before_keyframe_time = eval_keyframe_time;
|
||||||
} else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) {
|
} else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) {
|
||||||
after_keyframe_index = i;
|
after_keyframe_index = i;
|
||||||
after_keyframe_time = eval_keyframe_time;
|
after_keyframe_time = eval_keyframe_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) {
|
if ((type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) {
|
||||||
// interpolate
|
// interpolate
|
||||||
before = before_keyframe_index;
|
before = before_keyframe_index;
|
||||||
after = after_keyframe_index;
|
after = after_keyframe_index;
|
||||||
|
progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time));
|
||||||
progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time));
|
} else if (before_keyframe_index > -1) {
|
||||||
} else if (before_keyframe_index > -1) {
|
before = before_keyframe_index;
|
||||||
before = before_keyframe_index;
|
after = before_keyframe_index;
|
||||||
after = before_keyframe_index;
|
} else {
|
||||||
} else {
|
before = after_keyframe_index;
|
||||||
before = after_keyframe_index;
|
after = after_keyframe_index;
|
||||||
after = after_keyframe_index;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectField::hasKeyframes() {
|
bool EffectField::hasKeyframes() {
|
||||||
return (parent_row->isKeyframing() && keyframe_data.size() > 0);
|
return (parent_row->isKeyframing() && keyframes.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant EffectField::validate_keyframe_data(double timecode, bool async) {
|
QVariant EffectField::validate_keyframe_data(double timecode, bool async) {
|
||||||
if (hasKeyframes()) {
|
if (hasKeyframes()) {
|
||||||
int before_keyframe;
|
int before_keyframe;
|
||||||
int after_keyframe;
|
int after_keyframe;
|
||||||
double progress;
|
double progress;
|
||||||
get_keyframe_data(timecode, before_keyframe, after_keyframe, progress);
|
get_keyframe_data(timecode, before_keyframe, after_keyframe, progress);
|
||||||
|
|
||||||
int kf_type = (progress < 0.5) ? parent_row->keyframe_types.at(before_keyframe) : parent_row->keyframe_types.at(after_keyframe);
|
const QVariant& before_data = keyframes.at(before_keyframe).data;
|
||||||
if (kf_type == KEYFRAME_TYPE_SMOOTH) {
|
switch (type) {
|
||||||
double x = (8.0 * progress) - 4.0;
|
case EFFECT_FIELD_DOUBLE:
|
||||||
progress = 1.0 / (1.0 + qPow(M_E, -x));
|
{
|
||||||
progress *= 1.0373;
|
double value;
|
||||||
progress -= 0.01865;
|
if (before_keyframe == after_keyframe) {
|
||||||
}
|
value = keyframes.at(before_keyframe).data.toDouble();
|
||||||
|
} else {
|
||||||
|
const EffectKeyframe& before_key = keyframes.at(before_keyframe);
|
||||||
|
const EffectKeyframe& after_key = keyframes.at(after_keyframe);
|
||||||
|
|
||||||
const QVariant& before_data = keyframe_data.at(before_keyframe);
|
double before_dbl = before_key.data.toDouble();
|
||||||
switch (type) {
|
double after_dbl = after_key.data.toDouble();
|
||||||
case EFFECT_FIELD_DOUBLE:
|
|
||||||
{
|
if (before_key.type == KEYFRAME_TYPE_HOLD) {
|
||||||
double value;
|
// hold
|
||||||
if (before_keyframe == after_keyframe) {
|
value = before_dbl;
|
||||||
value = keyframe_data.at(before_keyframe).toDouble();
|
} else if (before_key.type == KEYFRAME_TYPE_BEZIER || after_key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
} else {
|
// bezier interpolation
|
||||||
double before_dbl = keyframe_data.at(before_keyframe).toDouble();
|
if (before_key.type == KEYFRAME_TYPE_BEZIER && after_key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
double after_dbl = keyframe_data.at(after_keyframe).toDouble();
|
// cubic bezier
|
||||||
value = double_lerp(before_dbl, after_dbl, progress);
|
double t = cubic_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+before_key.post_handle_x, after_key.time+after_key.pre_handle_x, after_key.time);
|
||||||
}
|
value = cubic_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl+after_key.pre_handle_y, after_dbl, t);
|
||||||
if (async) {
|
} else if (after_key.type == KEYFRAME_TYPE_LINEAR) { // quadratic bezier
|
||||||
return value;
|
// last keyframe is the bezier one
|
||||||
}
|
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+before_key.post_handle_x, after_key.time);
|
||||||
static_cast<LabelSlider*>(ui_element)->set_value(value, false);
|
value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t);
|
||||||
}
|
} else {
|
||||||
break;
|
// this keyframe is the bezier one
|
||||||
case EFFECT_FIELD_COLOR:
|
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+after_key.pre_handle_x, after_key.time);
|
||||||
{
|
value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t);
|
||||||
QColor value;
|
}
|
||||||
if (before_keyframe == after_keyframe) {
|
} else {
|
||||||
value = keyframe_data.at(before_keyframe).value<QColor>();
|
// linear
|
||||||
} else {
|
value = double_lerp(before_dbl, after_dbl, progress);
|
||||||
QColor before_data = keyframe_data.at(before_keyframe).value<QColor>();
|
}
|
||||||
QColor after_data = keyframe_data.at(after_keyframe).value<QColor>();
|
}
|
||||||
value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress));
|
if (async) {
|
||||||
}
|
return value;
|
||||||
if (async) {
|
}
|
||||||
return value;
|
static_cast<LabelSlider*>(ui_element)->set_value(value, false);
|
||||||
}
|
}
|
||||||
static_cast<ColorButton*>(ui_element)->set_color(value);
|
break;
|
||||||
}
|
case EFFECT_FIELD_COLOR:
|
||||||
break;
|
{
|
||||||
case EFFECT_FIELD_STRING:
|
QColor value;
|
||||||
if (async) {
|
if (before_keyframe == after_keyframe) {
|
||||||
return before_data;
|
value = keyframes.at(before_keyframe).data.value<QColor>();
|
||||||
}
|
} else {
|
||||||
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(before_data.toString());
|
QColor before_data = keyframes.at(before_keyframe).data.value<QColor>();
|
||||||
break;
|
QColor after_data = keyframes.at(after_keyframe).data.value<QColor>();
|
||||||
case EFFECT_FIELD_BOOL:
|
value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress));
|
||||||
if (async) {
|
}
|
||||||
return before_data;
|
if (async) {
|
||||||
}
|
return value;
|
||||||
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
|
}
|
||||||
break;
|
static_cast<ColorButton*>(ui_element)->set_color(value);
|
||||||
case EFFECT_FIELD_COMBO:
|
}
|
||||||
if (async) {
|
break;
|
||||||
return before_data;
|
case EFFECT_FIELD_STRING:
|
||||||
}
|
if (async) {
|
||||||
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
|
return before_data;
|
||||||
break;
|
}
|
||||||
case EFFECT_FIELD_FONT:
|
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(before_data.toString());
|
||||||
if (async) {
|
break;
|
||||||
return before_data;
|
case EFFECT_FIELD_BOOL:
|
||||||
}
|
if (async) {
|
||||||
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
|
return before_data;
|
||||||
break;
|
}
|
||||||
}
|
static_cast<QCheckBox*>(ui_element)->setChecked(before_data.toBool());
|
||||||
}
|
break;
|
||||||
return QVariant();
|
case EFFECT_FIELD_COMBO:
|
||||||
|
if (async) {
|
||||||
|
return before_data;
|
||||||
|
}
|
||||||
|
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(before_data.toInt());
|
||||||
|
break;
|
||||||
|
case EFFECT_FIELD_FONT:
|
||||||
|
if (async) {
|
||||||
|
return before_data;
|
||||||
|
}
|
||||||
|
static_cast<FontCombobox*>(ui_element)->setCurrentTextEx(before_data.toString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::ui_element_change() {
|
void EffectField::ui_element_change() {
|
||||||
bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(ui_element)->is_dragging());
|
bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(ui_element)->is_dragging());
|
||||||
ComboAction* ca = NULL;
|
ComboAction* ca = NULL;
|
||||||
if (!dragging_double) ca = new ComboAction();
|
if (!dragging_double) ca = new ComboAction();
|
||||||
make_key_from_change(ca);
|
make_key_from_change(ca);
|
||||||
if (!dragging_double) undo_stack.push(ca);
|
if (!dragging_double) undo_stack.push(ca);
|
||||||
emit changed();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::make_key_from_change(ComboAction* ca) {
|
void EffectField::make_key_from_change(ComboAction* ca) {
|
||||||
if (parent_row->isKeyframing()) {
|
if (parent_row->isKeyframing()) {
|
||||||
parent_row->set_keyframe_now(ca);
|
parent_row->set_keyframe_now(ca);
|
||||||
} else if (ca != NULL) {
|
} else if (ca != NULL) {
|
||||||
// set undo
|
// set undo
|
||||||
ca->append(new EffectFieldUndo(this));
|
ca->append(new EffectFieldUndo(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* EffectField::get_ui_element() {
|
QWidget* EffectField::get_ui_element() {
|
||||||
return ui_element;
|
return ui_element;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_enabled(bool e) {
|
void EffectField::set_enabled(bool e) {
|
||||||
ui_element->setEnabled(e);
|
ui_element->setEnabled(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
double EffectField::get_double_value(double timecode, bool async) {
|
double EffectField::get_double_value(double timecode, bool async) {
|
||||||
if (async && hasKeyframes()) {
|
if (async && hasKeyframes()) {
|
||||||
return validate_keyframe_data(timecode, true).toDouble();
|
return validate_keyframe_data(timecode, true).toDouble();
|
||||||
}
|
}
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<LabelSlider*>(ui_element)->value();
|
return static_cast<LabelSlider*>(ui_element)->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_double_value(double v) {
|
void EffectField::set_double_value(double v) {
|
||||||
static_cast<LabelSlider*>(ui_element)->set_value(v, false);
|
static_cast<LabelSlider*>(ui_element)->set_value(v, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_double_default_value(double v) {
|
void EffectField::set_double_default_value(double v) {
|
||||||
static_cast<LabelSlider*>(ui_element)->set_default_value(v);
|
static_cast<LabelSlider*>(ui_element)->set_default_value(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_double_minimum_value(double v) {
|
void EffectField::set_double_minimum_value(double v) {
|
||||||
static_cast<LabelSlider*>(ui_element)->set_minimum_value(v);
|
static_cast<LabelSlider*>(ui_element)->set_minimum_value(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_double_maximum_value(double v) {
|
void EffectField::set_double_maximum_value(double v) {
|
||||||
static_cast<LabelSlider*>(ui_element)->set_maximum_value(v);
|
static_cast<LabelSlider*>(ui_element)->set_maximum_value(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::add_combo_item(const QString& name, const QVariant& data) {
|
void EffectField::add_combo_item(const QString& name, const QVariant& data) {
|
||||||
static_cast<ComboBoxEx*>(ui_element)->addItem(name, data);
|
static_cast<ComboBoxEx*>(ui_element)->addItem(name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectField::get_combo_index(double timecode, bool async) {
|
int EffectField::get_combo_index(double timecode, bool async) {
|
||||||
if (async && hasKeyframes()) {
|
if (async && hasKeyframes()) {
|
||||||
return validate_keyframe_data(timecode, true).toInt();
|
return validate_keyframe_data(timecode, true).toInt();
|
||||||
}
|
}
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
|
return static_cast<ComboBoxEx*>(ui_element)->currentIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVariant EffectField::get_combo_data(double timecode) {
|
const QVariant EffectField::get_combo_data(double timecode) {
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<ComboBoxEx*>(ui_element)->currentData();
|
return static_cast<ComboBoxEx*>(ui_element)->currentData();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString EffectField::get_combo_string(double timecode) {
|
const QString EffectField::get_combo_string(double timecode) {
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<ComboBoxEx*>(ui_element)->currentText();
|
return static_cast<ComboBoxEx*>(ui_element)->currentText();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_combo_index(int index) {
|
void EffectField::set_combo_index(int index) {
|
||||||
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(index);
|
static_cast<ComboBoxEx*>(ui_element)->setCurrentIndexEx(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_combo_string(const QString& s) {
|
void EffectField::set_combo_string(const QString& s) {
|
||||||
static_cast<ComboBoxEx*>(ui_element)->setCurrentTextEx(s);
|
static_cast<ComboBoxEx*>(ui_element)->setCurrentTextEx(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectField::get_bool_value(double timecode, bool async) {
|
bool EffectField::get_bool_value(double timecode, bool async) {
|
||||||
if (async && hasKeyframes()) {
|
if (async && hasKeyframes()) {
|
||||||
return validate_keyframe_data(timecode, true).toBool();
|
return validate_keyframe_data(timecode, true).toBool();
|
||||||
}
|
}
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<QCheckBox*>(ui_element)->isChecked();
|
return static_cast<QCheckBox*>(ui_element)->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_bool_value(bool b) {
|
void EffectField::set_bool_value(bool b) {
|
||||||
return static_cast<QCheckBox*>(ui_element)->setChecked(b);
|
return static_cast<QCheckBox*>(ui_element)->setChecked(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString EffectField::get_string_value(double timecode, bool async) {
|
const QString EffectField::get_string_value(double timecode, bool async) {
|
||||||
if (async && hasKeyframes()) {
|
if (async && hasKeyframes()) {
|
||||||
return validate_keyframe_data(timecode, true).toString();
|
return validate_keyframe_data(timecode, true).toString();
|
||||||
}
|
}
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
|
return static_cast<TextEditEx*>(ui_element)->getPlainTextEx();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_string_value(const QString& s) {
|
void EffectField::set_string_value(const QString& s) {
|
||||||
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(s);
|
static_cast<TextEditEx*>(ui_element)->setPlainTextEx(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString EffectField::get_font_name(double timecode, bool async) {
|
const QString EffectField::get_font_name(double timecode, bool async) {
|
||||||
if (async && hasKeyframes()) {
|
if (async && hasKeyframes()) {
|
||||||
return validate_keyframe_data(timecode, true).toString();
|
return validate_keyframe_data(timecode, true).toString();
|
||||||
}
|
}
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<FontCombobox*>(ui_element)->currentText();
|
return static_cast<FontCombobox*>(ui_element)->currentText();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_font_name(const QString& s) {
|
void EffectField::set_font_name(const QString& s) {
|
||||||
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
|
static_cast<FontCombobox*>(ui_element)->setCurrentText(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor EffectField::get_color_value(double timecode, bool async) {
|
QColor EffectField::get_color_value(double timecode, bool async) {
|
||||||
if (async && hasKeyframes()) {
|
if (async && hasKeyframes()) {
|
||||||
return validate_keyframe_data(timecode, true).value<QColor>();
|
return validate_keyframe_data(timecode, true).value<QColor>();
|
||||||
}
|
}
|
||||||
validate_keyframe_data(timecode);
|
validate_keyframe_data(timecode);
|
||||||
return static_cast<ColorButton*>(ui_element)->get_color();
|
return static_cast<ColorButton*>(ui_element)->get_color();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectField::set_color_value(QColor color) {
|
void EffectField::set_color_value(QColor color) {
|
||||||
static_cast<ColorButton*>(ui_element)->set_color(color);
|
static_cast<ColorButton*>(ui_element)->set_color(color);
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-40
@@ -12,63 +12,66 @@
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "keyframe.h"
|
||||||
|
|
||||||
class EffectRow;
|
class EffectRow;
|
||||||
class ComboAction;
|
class ComboAction;
|
||||||
|
|
||||||
class EffectField : public QObject {
|
class EffectField : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
EffectField(EffectRow* parent, int t, const QString& i);
|
EffectField(EffectRow* parent, int t, const QString& i);
|
||||||
EffectRow* parent_row;
|
EffectRow* parent_row;
|
||||||
int type;
|
int type;
|
||||||
QString id;
|
QString id;
|
||||||
|
|
||||||
QVariant get_previous_data();
|
QVariant get_previous_data();
|
||||||
QVariant get_current_data();
|
QVariant get_current_data();
|
||||||
double frameToTimecode(long frame);
|
double frameToTimecode(long frame);
|
||||||
long timecodeToFrame(double timecode);
|
long timecodeToFrame(double timecode);
|
||||||
void set_current_data(const QVariant&);
|
void set_current_data(const QVariant&);
|
||||||
void get_keyframe_data(double timecode, int& before, int& after, double& d);
|
void get_keyframe_data(double timecode, int& before, int& after, double& d);
|
||||||
QVariant validate_keyframe_data(double timecode, bool async = false);
|
QVariant validate_keyframe_data(double timecode, bool async = false);
|
||||||
|
|
||||||
double get_double_value(double timecode, bool async = false);
|
double get_double_value(double timecode, bool async = false);
|
||||||
void set_double_value(double v);
|
void set_double_value(double v);
|
||||||
void set_double_default_value(double v);
|
void set_double_default_value(double v);
|
||||||
void set_double_minimum_value(double v);
|
void set_double_minimum_value(double v);
|
||||||
void set_double_maximum_value(double v);
|
void set_double_maximum_value(double v);
|
||||||
|
|
||||||
const QString get_string_value(double timecode, bool async = false);
|
const QString get_string_value(double timecode, bool async = false);
|
||||||
void set_string_value(const QString &s);
|
void set_string_value(const QString &s);
|
||||||
|
|
||||||
void add_combo_item(const QString& name, const QVariant &data);
|
void add_combo_item(const QString& name, const QVariant &data);
|
||||||
int get_combo_index(double timecode, bool async = false);
|
int get_combo_index(double timecode, bool async = false);
|
||||||
const QVariant get_combo_data(double timecode);
|
const QVariant get_combo_data(double timecode);
|
||||||
const QString get_combo_string(double timecode);
|
const QString get_combo_string(double timecode);
|
||||||
void set_combo_index(int index);
|
void set_combo_index(int index);
|
||||||
void set_combo_string(const QString& s);
|
void set_combo_string(const QString& s);
|
||||||
|
|
||||||
bool get_bool_value(double timecode, bool async = false);
|
bool get_bool_value(double timecode, bool async = false);
|
||||||
void set_bool_value(bool b);
|
void set_bool_value(bool b);
|
||||||
|
|
||||||
const QString get_font_name(double timecode, bool async = false);
|
const QString get_font_name(double timecode, bool async = false);
|
||||||
void set_font_name(const QString& s);
|
void set_font_name(const QString& s);
|
||||||
|
|
||||||
QColor get_color_value(double timecode, bool async = false);
|
QColor get_color_value(double timecode, bool async = false);
|
||||||
void set_color_value(QColor color);
|
void set_color_value(QColor color);
|
||||||
|
|
||||||
QWidget* get_ui_element();
|
QWidget* get_ui_element();
|
||||||
void set_enabled(bool e);
|
void set_enabled(bool e);
|
||||||
QVector<QVariant> keyframe_data;
|
QVector<EffectKeyframe> keyframes;
|
||||||
QWidget* ui_element;
|
QWidget* ui_element;
|
||||||
|
|
||||||
void make_key_from_change(ComboAction* ca);
|
void make_key_from_change(ComboAction* ca);
|
||||||
private:
|
private:
|
||||||
bool hasKeyframes();
|
bool hasKeyframes();
|
||||||
private slots:
|
private slots:
|
||||||
void ui_element_change();
|
void ui_element_change();
|
||||||
signals:
|
signals:
|
||||||
void changed();
|
void changed();
|
||||||
void toggled(bool);
|
void toggled(bool);
|
||||||
|
void clicked();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EFFECTFIELD_H
|
#endif // EFFECTFIELD_H
|
||||||
|
|||||||
+146
-119
@@ -1,6 +1,5 @@
|
|||||||
#include "effectrow.h"
|
#include "effectrow.h"
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
@@ -11,169 +10,197 @@
|
|||||||
#include "panels/panels.h"
|
#include "panels/panels.h"
|
||||||
#include "panels/effectcontrols.h"
|
#include "panels/effectcontrols.h"
|
||||||
#include "panels/viewer.h"
|
#include "panels/viewer.h"
|
||||||
|
#include "panels/grapheditor.h"
|
||||||
#include "effect.h"
|
#include "effect.h"
|
||||||
#include "ui/viewerwidget.h"
|
#include "ui/viewerwidget.h"
|
||||||
#include "ui/keyframenavigator.h"
|
#include "ui/keyframenavigator.h"
|
||||||
|
#include "ui/clickablelabel.h"
|
||||||
|
|
||||||
EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row) :
|
EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row) :
|
||||||
parent_effect(parent),
|
parent_effect(parent),
|
||||||
savable(save),
|
savable(save),
|
||||||
keyframing(false),
|
keyframing(false),
|
||||||
ui(uilayout),
|
ui(uilayout),
|
||||||
name(n),
|
name(n),
|
||||||
ui_row(row),
|
ui_row(row),
|
||||||
just_made_unsafe_keyframe(false)
|
just_made_unsafe_keyframe(false)
|
||||||
{
|
{
|
||||||
label = new QLabel(name);
|
label = new ClickableLabel(name + ":");
|
||||||
ui->addWidget(label, row, 0);
|
|
||||||
|
|
||||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
ui->addWidget(label, row, 0);
|
||||||
keyframe_nav = new KeyframeNavigator();
|
|
||||||
connect(keyframe_nav, SIGNAL(goto_previous_key()), this, SLOT(goto_previous_key()));
|
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||||
connect(keyframe_nav, SIGNAL(toggle_key()), this, SLOT(toggle_key()));
|
connect(label, SIGNAL(clicked()), this, SLOT(focus_row()));
|
||||||
connect(keyframe_nav, SIGNAL(goto_next_key()), this, SLOT(goto_next_key()));
|
|
||||||
connect(keyframe_nav, SIGNAL(set_keyframe_enabled(bool)), this, SLOT(set_keyframe_enabled(bool)));
|
keyframe_nav = new KeyframeNavigator();
|
||||||
ui->addWidget(keyframe_nav, row, 6);
|
connect(keyframe_nav, SIGNAL(goto_previous_key()), this, SLOT(goto_previous_key()));
|
||||||
}
|
connect(keyframe_nav, SIGNAL(toggle_key()), this, SLOT(toggle_key()));
|
||||||
|
connect(keyframe_nav, SIGNAL(goto_next_key()), this, SLOT(goto_next_key()));
|
||||||
|
connect(keyframe_nav, SIGNAL(keyframe_enabled_changed(bool)), this, SLOT(set_keyframe_enabled(bool)));
|
||||||
|
connect(keyframe_nav, SIGNAL(clicked()), this, SLOT(focus_row()));
|
||||||
|
ui->addWidget(keyframe_nav, row, 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectRow::isKeyframing() {
|
bool EffectRow::isKeyframing() {
|
||||||
return keyframing;
|
return keyframing;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::setKeyframing(bool b) {
|
void EffectRow::setKeyframing(bool b) {
|
||||||
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) {
|
||||||
keyframing = b;
|
keyframing = b;
|
||||||
keyframe_nav->enable_keyframes(b);
|
keyframe_nav->enable_keyframes(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::set_keyframe_enabled(bool enabled) {
|
void EffectRow::set_keyframe_enabled(bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
ComboAction* ca = new ComboAction();
|
ComboAction* ca = new ComboAction();
|
||||||
set_keyframe_now(ca);
|
set_keyframe_now(ca);
|
||||||
undo_stack.push(ca);
|
undo_stack.push(ca);
|
||||||
} else {
|
} else {
|
||||||
if (QMessageBox::question(panel_effect_controls, "Disable Keyframes", "Disabling keyframes will delete all current keyframes. Are you sure you want to do this?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
if (QMessageBox::question(panel_effect_controls, "Disable Keyframes", "Disabling keyframes will delete all current keyframes. Are you sure you want to do this?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
|
||||||
// clear
|
// clear
|
||||||
KeyframeDelete* kd = new KeyframeDelete();
|
ComboAction* ca = new ComboAction();
|
||||||
for (int i=keyframe_times.size()-1;i>=0;i--) {
|
for (int i=0;i<fieldCount();i++) {
|
||||||
delete_keyframe(kd, i);
|
EffectField* f = field(i);
|
||||||
}
|
for (int j=0;j<f->keyframes.size();j++) {
|
||||||
kd->disable_keyframes_on_row = this;
|
ca->append(new KeyframeDelete(f, 0));
|
||||||
undo_stack.push(kd);
|
}
|
||||||
panel_effect_controls->update_keyframes();
|
}
|
||||||
} else {
|
undo_stack.push(ca);
|
||||||
setKeyframing(true);
|
panel_effect_controls->update_keyframes();
|
||||||
}
|
} else {
|
||||||
}
|
setKeyframing(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::goto_previous_key() {
|
void EffectRow::goto_previous_key() {
|
||||||
long key = LONG_MIN;
|
long key = LONG_MIN;
|
||||||
Clip* c = parent_effect->parent_clip;
|
Clip* c = parent_effect->parent_clip;
|
||||||
for (int i=0;i<keyframe_times.size();i++) {
|
for (int i=0;i<fieldCount();i++) {
|
||||||
long comp = keyframe_times.at(i) - c->clip_in + c->timeline_in;
|
EffectField* f = field(i);
|
||||||
if (comp < sequence->playhead) {
|
for (int j=0;j<f->keyframes.size();j++) {
|
||||||
key = qMax(comp, key);
|
long comp = f->keyframes.at(j).time - c->clip_in + c->timeline_in;
|
||||||
}
|
if (comp < sequence->playhead) {
|
||||||
}
|
key = qMax(comp, key);
|
||||||
if (key != LONG_MIN) panel_sequence_viewer->seek(key);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key != LONG_MIN) panel_sequence_viewer->seek(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::toggle_key() {
|
void EffectRow::toggle_key() {
|
||||||
int index = -1;
|
QVector<EffectField*> key_fields;
|
||||||
Clip* c = parent_effect->parent_clip;
|
QVector<int> key_field_index;
|
||||||
for (int i=0;i<keyframe_times.size();i++) {
|
Clip* c = parent_effect->parent_clip;
|
||||||
long comp = c->timeline_in - c->clip_in + keyframe_times.at(i);
|
for (int j=0;j<fieldCount();j++) {
|
||||||
if (comp == sequence->playhead) {
|
EffectField* f = field(j);
|
||||||
index = i;
|
for (int i=0;i<f->keyframes.size();i++) {
|
||||||
break;
|
long comp = c->timeline_in - c->clip_in + f->keyframes.at(i).time;
|
||||||
}
|
if (comp == sequence->playhead) {
|
||||||
}
|
key_fields.append(f);
|
||||||
if (index < 0) {
|
key_field_index.append(i);
|
||||||
// keyframe doesn't exist, set one
|
}
|
||||||
ComboAction* ca = new ComboAction();
|
}
|
||||||
set_keyframe_now(ca);
|
}
|
||||||
undo_stack.push(ca);
|
|
||||||
} else {
|
ComboAction* ca = new ComboAction();
|
||||||
KeyframeDelete* kd = new KeyframeDelete();
|
if (key_fields.size() == 0) {
|
||||||
delete_keyframe(kd, index);
|
// keyframe doesn't exist, set one
|
||||||
undo_stack.push(kd);
|
set_keyframe_now(ca);
|
||||||
panel_effect_controls->update_keyframes();
|
} else {
|
||||||
panel_sequence_viewer->viewer_widget->update();
|
for (int i=0;i<key_fields.size();i++) {
|
||||||
}
|
ca->append(new KeyframeDelete(key_fields.at(i), key_field_index.at(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undo_stack.push(ca);
|
||||||
|
update_ui(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::goto_next_key() {
|
void EffectRow::goto_next_key() {
|
||||||
long key = LONG_MAX;
|
long key = LONG_MAX;
|
||||||
Clip* c = parent_effect->parent_clip;
|
Clip* c = parent_effect->parent_clip;
|
||||||
for (int i=0;i<keyframe_times.size();i++) {
|
for (int i=0;i<fieldCount();i++) {
|
||||||
long comp = c->timeline_in - c->clip_in + keyframe_times.at(i);
|
EffectField* f = field(i);
|
||||||
if (comp > sequence->playhead) {
|
for (int j=0;j<f->keyframes.size();j++) {
|
||||||
key = qMin(comp, key);
|
long comp = f->keyframes.at(j).time - c->clip_in + c->timeline_in;
|
||||||
}
|
if (comp > sequence->playhead) {
|
||||||
}
|
key = qMin(comp, key);
|
||||||
if (key != LONG_MAX) panel_sequence_viewer->seek(key);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key != LONG_MAX) panel_sequence_viewer->seek(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectRow::focus_row() {
|
||||||
|
panel_graph_editor->set_row(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectField* EffectRow::add_field(int type, const QString& id, int colspan) {
|
EffectField* EffectRow::add_field(int type, const QString& id, int colspan) {
|
||||||
EffectField* field = new EffectField(this, type, id);
|
EffectField* field = new EffectField(this, type, id);
|
||||||
fields.append(field);
|
if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row()));
|
||||||
QWidget* element = field->get_ui_element();
|
fields.append(field);
|
||||||
ui->addWidget(element, ui_row, fields.size(), 1, colspan);
|
QWidget* element = field->get_ui_element();
|
||||||
connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed()));
|
ui->addWidget(element, ui_row, fields.size(), 1, colspan);
|
||||||
return field;
|
connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed()));
|
||||||
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectRow::~EffectRow() {
|
EffectRow::~EffectRow() {
|
||||||
for (int i=0;i<fields.size();i++) {
|
for (int i=0;i<fields.size();i++) {
|
||||||
delete fields.at(i);
|
delete fields.at(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::set_keyframe_now(ComboAction* ca) {
|
void EffectRow::set_keyframe_now(ComboAction* ca) {
|
||||||
int index = -1;
|
int index = -1;
|
||||||
long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
|
long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in;
|
||||||
for (int i=0;i<keyframe_times.size();i++) {
|
for (int j=0;j<fieldCount();j++) {
|
||||||
if (keyframe_times.at(i) == time) {
|
EffectField* f = field(j);
|
||||||
index = i;
|
for (int i=0;i<f->keyframes.size();i++) {
|
||||||
break;
|
if (f->keyframes.at(i).time == time) {
|
||||||
}
|
index = i;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe);
|
KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe);
|
||||||
|
|
||||||
if (ca != NULL) {
|
if (ca != NULL) {
|
||||||
just_made_unsafe_keyframe = false;
|
just_made_unsafe_keyframe = false;
|
||||||
ca->append(ks);
|
ca->append(ks);
|
||||||
} else {
|
} else {
|
||||||
if (index == -1) just_made_unsafe_keyframe = true;
|
if (index == -1) just_made_unsafe_keyframe = true;
|
||||||
ks->redo();
|
ks->redo();
|
||||||
delete ks;
|
delete ks;
|
||||||
}
|
}
|
||||||
|
|
||||||
panel_effect_controls->update_keyframes();
|
panel_effect_controls->update_keyframes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::delete_keyframe_at_time(KeyframeDelete* kd, long time) {
|
void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) {
|
||||||
for (int i=0;i<keyframe_times.size();i++) {
|
for (int j=0;j<fieldCount();j++) {
|
||||||
if (keyframe_times.at(i) == time) {
|
EffectField* f = field(j);
|
||||||
delete_keyframe(kd, i);
|
for (int i=0;i<f->keyframes.size();i++) {
|
||||||
break;
|
if (f->keyframes.at(i).time == time) {
|
||||||
}
|
ca->append(new KeyframeDelete(f, i));
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectRow::delete_keyframe(KeyframeDelete* kd, int index) {
|
const QString &EffectRow::get_name() {
|
||||||
kd->rows.append(this);
|
return name;
|
||||||
kd->keyframes.append(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectField* EffectRow::field(int i) {
|
EffectField* EffectRow::field(int i) {
|
||||||
return fields.at(i);
|
return fields.at(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectRow::fieldCount() {
|
int EffectRow::fieldCount() {
|
||||||
return fields.size();
|
return fields.size();
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-29
@@ -8,47 +8,46 @@ class Effect;
|
|||||||
class QGridLayout;
|
class QGridLayout;
|
||||||
class EffectField;
|
class EffectField;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class KeyframeDelete;
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class ComboAction;
|
class ComboAction;
|
||||||
class QHBoxLayout;
|
class QHBoxLayout;
|
||||||
class KeyframeNavigator;
|
class KeyframeNavigator;
|
||||||
|
class ClickableLabel;
|
||||||
|
|
||||||
class EffectRow : public QObject {
|
class EffectRow : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row);
|
EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row);
|
||||||
~EffectRow();
|
~EffectRow();
|
||||||
EffectField* add_field(int type, const QString &id, int colspan = 1);
|
EffectField* add_field(int type, const QString &id, int colspan = 1);
|
||||||
EffectField* field(int i);
|
EffectField* field(int i);
|
||||||
int fieldCount();
|
int fieldCount();
|
||||||
void set_keyframe_now(ComboAction *ca);
|
void set_keyframe_now(ComboAction *ca);
|
||||||
void delete_keyframe(KeyframeDelete *kd, int index);
|
void delete_keyframe_at_time(ComboAction *ca, long time);
|
||||||
void delete_keyframe_at_time(KeyframeDelete* kd, long time);
|
ClickableLabel* label;
|
||||||
QLabel* label;
|
Effect* parent_effect;
|
||||||
Effect* parent_effect;
|
bool savable;
|
||||||
bool savable;
|
const QString& get_name();
|
||||||
|
|
||||||
bool isKeyframing();
|
bool isKeyframing();
|
||||||
void setKeyframing(bool);
|
void setKeyframing(bool);
|
||||||
|
public slots:
|
||||||
QVector<long> keyframe_times;
|
void goto_previous_key();
|
||||||
QVector<int> keyframe_types;
|
void toggle_key();
|
||||||
|
void goto_next_key();
|
||||||
|
void focus_row();
|
||||||
private slots:
|
private slots:
|
||||||
void set_keyframe_enabled(bool);
|
void set_keyframe_enabled(bool);
|
||||||
void goto_previous_key();
|
|
||||||
void toggle_key();
|
|
||||||
void goto_next_key();
|
|
||||||
private:
|
private:
|
||||||
bool keyframing;
|
bool keyframing;
|
||||||
QGridLayout* ui;
|
QGridLayout* ui;
|
||||||
QString name;
|
QString name;
|
||||||
int ui_row;
|
int ui_row;
|
||||||
QVector<EffectField*> fields;
|
QVector<EffectField*> fields;
|
||||||
|
|
||||||
KeyframeNavigator* keyframe_nav;
|
KeyframeNavigator* keyframe_nav;
|
||||||
|
|
||||||
bool just_made_unsafe_keyframe;
|
bool just_made_unsafe_keyframe;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EFFECTROW_H
|
#endif // EFFECTROW_H
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#include "keyframe.h"
|
||||||
|
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "effectfield.h"
|
||||||
|
#include "undo.h"
|
||||||
|
#include "panels/panels.h"
|
||||||
|
|
||||||
|
EffectKeyframe::EffectKeyframe() {
|
||||||
|
pre_handle_x = -40;
|
||||||
|
pre_handle_y = 0;
|
||||||
|
post_handle_x = 40;
|
||||||
|
post_handle_y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_keyframes(QVector<EffectField *>& selected_key_fields, QVector<int> &selected_keys) {
|
||||||
|
QVector<EffectField*> fields;
|
||||||
|
QVector<int> key_indices;
|
||||||
|
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
bool added = false;
|
||||||
|
for (int j=0;j<key_indices.size();j++) {
|
||||||
|
if (key_indices.at(j) < selected_keys.at(i)) {
|
||||||
|
key_indices.insert(j, selected_keys.at(i));
|
||||||
|
fields.insert(j, selected_key_fields.at(i));
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!added) {
|
||||||
|
key_indices.append(selected_keys.at(i));
|
||||||
|
fields.append(selected_key_fields.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.size() > 0) {
|
||||||
|
ComboAction* ca = new ComboAction();
|
||||||
|
for (int i=0;i<key_indices.size();i++) {
|
||||||
|
ca->append(new KeyframeDelete(fields.at(i), key_indices.at(i)));
|
||||||
|
}
|
||||||
|
undo_stack.push(ca);
|
||||||
|
selected_keys.clear();
|
||||||
|
selected_key_fields.clear();
|
||||||
|
update_ui(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef KEYFRAME_H
|
||||||
|
#define KEYFRAME_H
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
class EffectField;
|
||||||
|
|
||||||
|
class EffectKeyframe {
|
||||||
|
public:
|
||||||
|
EffectKeyframe();
|
||||||
|
|
||||||
|
long time;
|
||||||
|
int type;
|
||||||
|
QVariant data;
|
||||||
|
|
||||||
|
// only for bezier type
|
||||||
|
double pre_handle_x;
|
||||||
|
double pre_handle_y;
|
||||||
|
double post_handle_x;
|
||||||
|
double post_handle_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
void delete_keyframes(QVector<EffectField *> &selected_key_fields, QVector<int> &selected_keys);
|
||||||
|
|
||||||
|
#endif // KEYFRAME_H
|
||||||
+92
-91
@@ -150,7 +150,7 @@ void DeleteClipAction::redo() {
|
|||||||
// remove ref to clip
|
// remove ref to clip
|
||||||
ref = seq->clips.at(index);
|
ref = seq->clips.at(index);
|
||||||
if (ref->open) {
|
if (ref->open) {
|
||||||
close_clip(ref);
|
close_clip(ref, true);
|
||||||
}
|
}
|
||||||
seq->clips[index] = NULL;
|
seq->clips[index] = NULL;
|
||||||
|
|
||||||
@@ -493,7 +493,7 @@ void AddClipCommand::undo() {
|
|||||||
Clip* c = seq->clips.last();
|
Clip* c = seq->clips.last();
|
||||||
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
|
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
|
||||||
undone_clips.prepend(c);
|
undone_clips.prepend(c);
|
||||||
if (c->open) close_clip(c);
|
if (c->open) close_clip(c, true);
|
||||||
seq->clips.removeLast();
|
seq->clips.removeLast();
|
||||||
}
|
}
|
||||||
mainWindow->setWindowModified(old_project_changed);
|
mainWindow->setWindowModified(old_project_changed);
|
||||||
@@ -587,8 +587,7 @@ void ReplaceMediaCommand::replace(QString& filename) {
|
|||||||
for (int j=0;j<s->clips.size();j++) {
|
for (int j=0;j<s->clips.size();j++) {
|
||||||
Clip* c = s->clips.at(j);
|
Clip* c = s->clips.at(j);
|
||||||
if (c != NULL && c->media == item && c->open) {
|
if (c != NULL && c->media == item && c->open) {
|
||||||
close_clip(c);
|
close_clip(c, true);
|
||||||
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
|
|
||||||
c->replaced = true;
|
c->replaced = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,8 +627,7 @@ void ReplaceClipMediaCommand::replace(bool undo) {
|
|||||||
for (int i=0;i<clips.size();i++) {
|
for (int i=0;i<clips.size();i++) {
|
||||||
Clip* c = clips.at(i);
|
Clip* c = clips.at(i);
|
||||||
if (c->open) {
|
if (c->open) {
|
||||||
close_clip(c);
|
close_clip(c, true);
|
||||||
if (c->media != NULL && c->media->get_type() == MEDIA_TYPE_FOOTAGE) c->cacher->wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (undo) {
|
if (undo) {
|
||||||
@@ -737,85 +735,21 @@ void MediaRename::redo() {
|
|||||||
mainWindow->setWindowModified(true);
|
mainWindow->setWindowModified(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyframeMove::KeyframeMove() : old_project_changed(mainWindow->isWindowModified()) {}
|
KeyframeDelete::KeyframeDelete(EffectField *ifield, int iindex) :
|
||||||
|
field(ifield),
|
||||||
void KeyframeMove::undo() {
|
index(iindex),
|
||||||
for (int i=0;i<rows.size();i++) {
|
old_project_changed(mainWindow->isWindowModified())
|
||||||
rows.at(i)->keyframe_times[keyframes.at(i)] -= movement;
|
|
||||||
}
|
|
||||||
mainWindow->setWindowModified(old_project_changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyframeMove::redo() {
|
|
||||||
for (int i=0;i<rows.size();i++) {
|
|
||||||
rows.at(i)->keyframe_times[keyframes.at(i)] += movement;
|
|
||||||
}
|
|
||||||
mainWindow->setWindowModified(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyframeDelete::KeyframeDelete() :
|
|
||||||
disable_keyframes_on_row(NULL),
|
|
||||||
old_project_changed(mainWindow->isWindowModified()),
|
|
||||||
sorted(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void KeyframeDelete::undo() {
|
void KeyframeDelete::undo() {
|
||||||
if (disable_keyframes_on_row != NULL) disable_keyframes_on_row->setKeyframing(true);
|
field->keyframes.insert(index, deleted_key);
|
||||||
|
|
||||||
int data_index = deleted_keyframe_data.size()-1;
|
|
||||||
for (int i=rows.size()-1;i>=0;i--) {
|
|
||||||
EffectRow* row = rows.at(i);
|
|
||||||
int keyframe_index = keyframes.at(i);
|
|
||||||
|
|
||||||
row->keyframe_times.insert(keyframe_index, deleted_keyframe_times.at(i));
|
|
||||||
row->keyframe_types.insert(keyframe_index, deleted_keyframe_types.at(i));
|
|
||||||
|
|
||||||
for (int j=row->fieldCount()-1;j>=0;j--) {
|
|
||||||
row->field(j)->keyframe_data.insert(keyframe_index, deleted_keyframe_data.at(data_index));
|
|
||||||
data_index--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mainWindow->setWindowModified(old_project_changed);
|
mainWindow->setWindowModified(old_project_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeDelete::redo() {
|
void KeyframeDelete::redo() {
|
||||||
if (!sorted) {
|
deleted_key = field->keyframes.at(index);
|
||||||
deleted_keyframe_times.resize(rows.size());
|
field->keyframes.removeAt(index);
|
||||||
deleted_keyframe_types.resize(rows.size());
|
|
||||||
deleted_keyframe_data.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0;i<keyframes.size();i++) {
|
|
||||||
EffectRow* row = rows.at(i);
|
|
||||||
int keyframe_index = keyframes.at(i);
|
|
||||||
|
|
||||||
if (!sorted) {
|
|
||||||
deleted_keyframe_times[i] = (row->keyframe_times.at(keyframe_index));
|
|
||||||
deleted_keyframe_types[i] = (row->keyframe_types.at(keyframe_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
row->keyframe_times.removeAt(keyframe_index);
|
|
||||||
row->keyframe_types.removeAt(keyframe_index);
|
|
||||||
|
|
||||||
for (int j=0;j<row->fieldCount();j++) {
|
|
||||||
if (!sorted) deleted_keyframe_data.append(row->field(j)->keyframe_data.at(keyframe_index));
|
|
||||||
row->field(j)->keyframe_data.removeAt(keyframe_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// correct following indices
|
|
||||||
if (!sorted) {
|
|
||||||
for (int j=i+1;j<keyframes.size();j++) {
|
|
||||||
if (rows.at(j) == row && keyframes.at(j) > keyframe_index) {
|
|
||||||
keyframes[j]--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disable_keyframes_on_row != NULL) disable_keyframes_on_row->setKeyframing(false);
|
|
||||||
mainWindow->setWindowModified(true);
|
mainWindow->setWindowModified(true);
|
||||||
sorted = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
|
KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
|
||||||
@@ -835,7 +769,7 @@ KeyframeSet::KeyframeSet(EffectRow* r, int i, long t, bool justMadeKeyframe) :
|
|||||||
if (field->type == EFFECT_FIELD_DOUBLE) {
|
if (field->type == EFFECT_FIELD_DOUBLE) {
|
||||||
old_values[i] = static_cast<LabelSlider*>(field->ui_element)->getPreviousValue();
|
old_values[i] = static_cast<LabelSlider*>(field->ui_element)->getPreviousValue();
|
||||||
} else {
|
} else {
|
||||||
old_values[i] = field->keyframe_data.at(index);
|
old_values[i] = field->keyframes.at(index).data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_values[i] = field->get_current_data();
|
new_values[i] = field->get_current_data();
|
||||||
@@ -846,15 +780,11 @@ void KeyframeSet::undo() {
|
|||||||
if (enable_keyframes) row->setKeyframing(false);
|
if (enable_keyframes) row->setKeyframing(false);
|
||||||
|
|
||||||
bool append = (index == -1 || just_made_keyframe);
|
bool append = (index == -1 || just_made_keyframe);
|
||||||
if (append) {
|
|
||||||
row->keyframe_times.removeLast();
|
|
||||||
row->keyframe_types.removeLast();
|
|
||||||
}
|
|
||||||
for (int i=0;i<row->fieldCount();i++) {
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
if (append) {
|
if (append) {
|
||||||
row->field(i)->keyframe_data.removeLast();
|
row->field(i)->keyframes.removeLast();
|
||||||
} else {
|
} else {
|
||||||
row->field(i)->keyframe_data[index] = old_values.at(i);
|
row->field(i)->keyframes[index].data = old_values.at(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,15 +794,16 @@ void KeyframeSet::undo() {
|
|||||||
|
|
||||||
void KeyframeSet::redo() {
|
void KeyframeSet::redo() {
|
||||||
bool append = (index == -1 || (just_made_keyframe && !done));
|
bool append = (index == -1 || (just_made_keyframe && !done));
|
||||||
if (append) {
|
|
||||||
row->keyframe_times.append(time);
|
|
||||||
row->keyframe_types.append((row->keyframe_types.size() > 0) ? row->keyframe_types.last() : EFFECT_KEYFRAME_LINEAR);
|
|
||||||
}
|
|
||||||
for (int i=0;i<row->fieldCount();i++) {
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
EffectField* f = row->field(i);
|
||||||
if (append) {
|
if (append) {
|
||||||
row->field(i)->keyframe_data.append(new_values.at(i));
|
EffectKeyframe k;
|
||||||
|
k.data = new_values.at(i);
|
||||||
|
k.time = time;
|
||||||
|
k.type = (f->keyframes.size() > 0) ? f->keyframes.last().type : EFFECT_KEYFRAME_LINEAR;
|
||||||
|
f->keyframes.append(k);
|
||||||
} else {
|
} else {
|
||||||
row->field(i)->keyframe_data[index] = new_values.at(i);
|
f->keyframes[index].data = new_values.at(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
row->setKeyframing(true);
|
row->setKeyframing(true);
|
||||||
@@ -1169,7 +1100,7 @@ void CloseAllClipsCommand::undo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CloseAllClipsCommand::redo() {
|
void CloseAllClipsCommand::redo() {
|
||||||
closeActiveClips(sequence, true);
|
closeActiveClips(sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateFootageTooltip::UpdateFootageTooltip(Media *i) :
|
UpdateFootageTooltip::UpdateFootageTooltip(Media *i) :
|
||||||
@@ -1290,3 +1221,73 @@ void RippleAction::redo() {
|
|||||||
}
|
}
|
||||||
ca->redo();
|
ca->redo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetDouble::SetDouble(double* pointer, double old_value, double new_value) :
|
||||||
|
p(pointer),
|
||||||
|
oldval(old_value),
|
||||||
|
newval(new_value),
|
||||||
|
old_project_changed(mainWindow->isWindowModified())
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetDouble::undo() {
|
||||||
|
*p = oldval;
|
||||||
|
mainWindow->setWindowModified(old_project_changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDouble::redo() {
|
||||||
|
*p = newval;
|
||||||
|
mainWindow->setWindowModified(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetQVariant::SetQVariant(QVariant *itarget, const QVariant &iold, const QVariant &inew) :
|
||||||
|
target(itarget),
|
||||||
|
old_val(iold),
|
||||||
|
new_val(inew)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetQVariant::undo() {
|
||||||
|
*target = old_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetQVariant::redo() {
|
||||||
|
*target = new_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetLong::SetLong(long *pointer, long old_value, long new_value) :
|
||||||
|
p(pointer),
|
||||||
|
oldval(old_value),
|
||||||
|
newval(new_value),
|
||||||
|
old_project_changed(mainWindow->isWindowModified())
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetLong::undo() {
|
||||||
|
*p = oldval;
|
||||||
|
mainWindow->setWindowModified(old_project_changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLong::redo() {
|
||||||
|
*p = newval;
|
||||||
|
mainWindow->setWindowModified(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyframeFieldSet::KeyframeFieldSet(EffectField *ifield, int ii) :
|
||||||
|
field(ifield),
|
||||||
|
index(ii),
|
||||||
|
key(ifield->keyframes.at(ii)),
|
||||||
|
done(true),
|
||||||
|
old_project_changed(mainWindow->isWindowModified())
|
||||||
|
{}
|
||||||
|
|
||||||
|
void KeyframeFieldSet::undo() {
|
||||||
|
field->keyframes.removeAt(index);
|
||||||
|
mainWindow->setWindowModified(old_project_changed);
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeFieldSet::redo() {
|
||||||
|
if (!done) {
|
||||||
|
field->keyframes.insert(index, key);
|
||||||
|
mainWindow->setWindowModified(true);
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|||||||
+56
-20
@@ -17,6 +17,7 @@ struct EffectMeta;
|
|||||||
|
|
||||||
#include "project/marker.h"
|
#include "project/marker.h"
|
||||||
#include "project/selection.h"
|
#include "project/selection.h"
|
||||||
|
#include "project/effectfield.h"
|
||||||
|
|
||||||
#include <QUndoStack>
|
#include <QUndoStack>
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
@@ -328,32 +329,17 @@ private:
|
|||||||
QString to;
|
QString to;
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyframeMove : public QUndoCommand {
|
|
||||||
public:
|
|
||||||
KeyframeMove();
|
|
||||||
QVector<EffectRow*> rows;
|
|
||||||
QVector<int> keyframes;
|
|
||||||
long movement;
|
|
||||||
void undo();
|
|
||||||
void redo();
|
|
||||||
private:
|
|
||||||
bool old_project_changed;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeyframeDelete : public QUndoCommand {
|
class KeyframeDelete : public QUndoCommand {
|
||||||
public:
|
public:
|
||||||
KeyframeDelete();
|
KeyframeDelete(EffectField* ifield, int iindex);
|
||||||
QVector<EffectRow*> rows;
|
|
||||||
EffectRow* disable_keyframes_on_row;
|
|
||||||
QVector<int> keyframes;
|
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
private:
|
private:
|
||||||
|
EffectField* field;
|
||||||
|
int index;
|
||||||
|
bool done;
|
||||||
|
EffectKeyframe deleted_key;
|
||||||
bool old_project_changed;
|
bool old_project_changed;
|
||||||
QVector<long> deleted_keyframe_times;
|
|
||||||
QVector<int> deleted_keyframe_types;
|
|
||||||
QVector<QVariant> deleted_keyframe_data;
|
|
||||||
bool sorted;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -374,6 +360,21 @@ private:
|
|||||||
bool done;
|
bool done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// a more modern version of the above, could probably replace it
|
||||||
|
// assumes the keyframe already exists
|
||||||
|
class KeyframeFieldSet : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
KeyframeFieldSet(EffectField* ifield, int ii);
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
private:
|
||||||
|
EffectField* field;
|
||||||
|
int index;
|
||||||
|
EffectKeyframe key;
|
||||||
|
bool done;
|
||||||
|
bool old_project_changed;
|
||||||
|
};
|
||||||
|
|
||||||
class EffectFieldUndo : public QUndoCommand {
|
class EffectFieldUndo : public QUndoCommand {
|
||||||
public:
|
public:
|
||||||
EffectFieldUndo(EffectField* field);
|
EffectFieldUndo(EffectField* field);
|
||||||
@@ -523,6 +524,30 @@ private:
|
|||||||
bool old_project_changed;
|
bool old_project_changed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SetLong : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
SetLong(long* pointer, long old_value, long new_value);
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
private:
|
||||||
|
long* p;
|
||||||
|
long oldval;
|
||||||
|
long newval;
|
||||||
|
bool old_project_changed;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetDouble : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
SetDouble(double* pointer, double old_value, double new_value);
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
private:
|
||||||
|
double* p;
|
||||||
|
double oldval;
|
||||||
|
double newval;
|
||||||
|
bool old_project_changed;
|
||||||
|
};
|
||||||
|
|
||||||
class SetString : public QUndoCommand {
|
class SetString : public QUndoCommand {
|
||||||
public:
|
public:
|
||||||
SetString(QString* pointer, QString new_value);
|
SetString(QString* pointer, QString new_value);
|
||||||
@@ -605,4 +630,15 @@ public:
|
|||||||
void redo();
|
void redo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SetQVariant : public QUndoCommand {
|
||||||
|
public:
|
||||||
|
SetQVariant(QVariant* itarget, const QVariant& iold, const QVariant& inew);
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
private:
|
||||||
|
QVariant* target;
|
||||||
|
QVariant old_val;
|
||||||
|
QVariant new_val;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // UNDO_H
|
#endif // UNDO_H
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "clickablelabel.h"
|
||||||
|
|
||||||
|
ClickableLabel::ClickableLabel(QWidget *parent, Qt::WindowFlags f) :
|
||||||
|
QLabel(parent, f)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ClickableLabel::ClickableLabel(const QString &text, QWidget *parent, Qt::WindowFlags f) :
|
||||||
|
QLabel(text, parent, f)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ClickableLabel::mousePressEvent(QMouseEvent *) {
|
||||||
|
emit clicked();
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef CLICKABLELABEL_H
|
||||||
|
#define CLICKABLELABEL_H
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
class ClickableLabel : public QLabel {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ClickableLabel(QWidget * parent = 0, Qt::WindowFlags f = 0);
|
||||||
|
ClickableLabel(const QString & text, QWidget * parent = 0, Qt::WindowFlags f = 0);
|
||||||
|
void mousePressEvent(QMouseEvent *ev);
|
||||||
|
signals:
|
||||||
|
void clicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CLICKABLELABEL_H
|
||||||
@@ -0,0 +1,835 @@
|
|||||||
|
#include "graphview.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QtMath>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
|
#include "panels/panels.h"
|
||||||
|
#include "panels/timeline.h"
|
||||||
|
#include "panels/viewer.h"
|
||||||
|
#include "project/sequence.h"
|
||||||
|
#include "project/effectrow.h"
|
||||||
|
#include "project/effectfield.h"
|
||||||
|
#include "ui/keyframedrawing.h"
|
||||||
|
#include "project/undo.h"
|
||||||
|
#include "project/effect.h"
|
||||||
|
#include "project/clip.h"
|
||||||
|
#include "ui/rectangleselect.h"
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define GRAPH_ZOOM_SPEED 0.05
|
||||||
|
#define GRAPH_SIZE 100
|
||||||
|
#define BEZIER_HANDLE_SIZE 3
|
||||||
|
#define BEZIER_LINE_SIZE 2
|
||||||
|
|
||||||
|
#define BEZIER_HANDLE_NONE 1
|
||||||
|
#define BEZIER_HANDLE_PRE 2
|
||||||
|
#define BEZIER_HANDLE_POST 3
|
||||||
|
|
||||||
|
QColor get_curve_color(int index, int length) {
|
||||||
|
QColor c;
|
||||||
|
int hue = qRound((double(index)/double(length))*255);
|
||||||
|
c.setHsv(hue, 255, 255);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphView::GraphView(QWidget* parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
x_scroll(0),
|
||||||
|
y_scroll(0),
|
||||||
|
mousedown(false),
|
||||||
|
zoom(1.0),
|
||||||
|
row(NULL),
|
||||||
|
moved_keys(false),
|
||||||
|
current_handle(BEZIER_HANDLE_NONE),
|
||||||
|
rect_select(false),
|
||||||
|
visible_in(0)
|
||||||
|
{
|
||||||
|
setMouseTracking(true);
|
||||||
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::show_context_menu(const QPoint& pos) {
|
||||||
|
QMenu menu(this);
|
||||||
|
|
||||||
|
QAction* zoom_to_selection = menu.addAction("Zoom to Selection");
|
||||||
|
if (selected_keys.size() == 0) {
|
||||||
|
zoom_to_selection->setEnabled(false);
|
||||||
|
} else {
|
||||||
|
connect(zoom_to_selection, SIGNAL(triggered(bool)), this, SLOT(set_view_to_selection()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* zoom_to_all = menu.addAction("Zoom to Show All");
|
||||||
|
connect(zoom_to_all, SIGNAL(triggered(bool)), this, SLOT(set_view_to_all()));
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
|
QAction* reset_action = menu.addAction("Reset View");
|
||||||
|
connect(reset_action, SIGNAL(triggered(bool)), this, SLOT(reset_view()));
|
||||||
|
|
||||||
|
menu.exec(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::reset_view() {
|
||||||
|
zoom = 1.0;
|
||||||
|
set_scroll_x(0);
|
||||||
|
set_scroll_y(0);
|
||||||
|
emit zoom_changed(zoom);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_view_to_selection() {
|
||||||
|
if (selected_keys.size() > 0) {
|
||||||
|
long min_time = LONG_MAX;
|
||||||
|
long max_time = LONG_MIN;
|
||||||
|
double min_dbl = DBL_MAX;
|
||||||
|
double max_dbl = DBL_MIN;
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
const EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
|
||||||
|
min_time = qMin(key.time, min_time);
|
||||||
|
max_time = qMax(key.time, max_time);
|
||||||
|
min_dbl = qMin(key.data.toDouble(), min_dbl);
|
||||||
|
max_dbl = qMax(key.data.toDouble(), max_dbl);
|
||||||
|
}
|
||||||
|
set_view_to_rect(min_time, min_dbl, max_time, max_dbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_view_to_all() {
|
||||||
|
bool can_set = false;
|
||||||
|
|
||||||
|
long min_time = LONG_MAX;
|
||||||
|
long max_time = LONG_MIN;
|
||||||
|
double min_dbl = DBL_MAX;
|
||||||
|
double max_dbl = DBL_MIN;
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
for (int j=0;j<row->field(i)->keyframes.size();j++) {
|
||||||
|
const EffectKeyframe& key = row->field(i)->keyframes.at(j);
|
||||||
|
min_time = qMin(key.time, min_time);
|
||||||
|
max_time = qMax(key.time, max_time);
|
||||||
|
min_dbl = qMin(key.data.toDouble(), min_dbl);
|
||||||
|
max_dbl = qMax(key.data.toDouble(), max_dbl);
|
||||||
|
can_set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_set) {
|
||||||
|
set_view_to_rect(min_time, min_dbl, max_time, max_dbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_view_to_rect(int x1, double y1, int x2, double y2) {
|
||||||
|
double padding = 1.5;
|
||||||
|
double x_diff = double(x2 - x1);
|
||||||
|
double y_diff = (y2 - y1);
|
||||||
|
double x_diff_padded = (x_diff+10)*padding;
|
||||||
|
double y_diff_padded = (y_diff+10)*padding;
|
||||||
|
set_zoom(qMin(double(width()) / x_diff_padded, double(height()) / y_diff_padded));
|
||||||
|
|
||||||
|
set_scroll_x(qRound((double(x1) - ((x_diff_padded-x_diff)/2))*zoom));
|
||||||
|
set_scroll_y(qRound((double(y1) - ((y_diff_padded-y_diff)/2))*zoom));
|
||||||
|
|
||||||
|
//set_scroll_y(height() - y1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos) {
|
||||||
|
// draws last line's text
|
||||||
|
QString str = QString::number(line_no*GRAPH_SIZE);
|
||||||
|
int text_sz = vert ? fontMetrics().height() : fontMetrics().width(str);
|
||||||
|
if (text_sz < (next_line_pos - line_pos)) {
|
||||||
|
QRect text_rect = vert ? QRect(0, line_pos-50, 50, 50) : QRect(line_pos, height()-50, 50, 50);
|
||||||
|
p.drawText(text_rect, Qt::AlignBottom | Qt::AlignLeft, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::draw_lines(QPainter& p, bool vert) {
|
||||||
|
int last_line = INT_MIN;
|
||||||
|
int last_line_x = INT_MIN;
|
||||||
|
int lim = vert ? height() : width();
|
||||||
|
int scroll = vert ? y_scroll : x_scroll;
|
||||||
|
for (int i=0;i<lim;i++) {
|
||||||
|
int scroll_offs = vert ? height() - i + scroll : i + scroll;
|
||||||
|
int this_line = qFloor(scroll_offs/(GRAPH_SIZE*zoom));
|
||||||
|
if (vert) this_line++;
|
||||||
|
if (this_line != last_line) {
|
||||||
|
if (vert) {
|
||||||
|
p.drawLine(0, i, width(), i);
|
||||||
|
} else {
|
||||||
|
p.drawLine(i, 0, i, height());
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_line_text(p, vert, last_line, last_line_x, i);
|
||||||
|
|
||||||
|
last_line_x = i;
|
||||||
|
last_line = this_line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_line_text(p, vert, last_line, last_line_x, width());
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<int> sort_keys_from_field(EffectField* field) {
|
||||||
|
QVector<int> sorted_keys;
|
||||||
|
for (int k=0;k<field->keyframes.size();k++) {
|
||||||
|
bool inserted = false;
|
||||||
|
for (int j=0;j<sorted_keys.size();j++) {
|
||||||
|
if (field->keyframes.at(sorted_keys.at(j)).time > field->keyframes.at(k).time) {
|
||||||
|
sorted_keys.insert(j, k);
|
||||||
|
inserted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inserted) {
|
||||||
|
sorted_keys.append(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sorted_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::paintEvent(QPaintEvent *) {
|
||||||
|
QPainter p(this);
|
||||||
|
|
||||||
|
if (panel_sequence_viewer->seq != NULL) {
|
||||||
|
// draw grid lines
|
||||||
|
|
||||||
|
p.setPen(Qt::gray);
|
||||||
|
|
||||||
|
draw_lines(p, true);
|
||||||
|
draw_lines(p, false);
|
||||||
|
|
||||||
|
// draw keyframes
|
||||||
|
if (row != NULL) {
|
||||||
|
QPen line_pen;
|
||||||
|
line_pen.setWidth(BEZIER_LINE_SIZE);
|
||||||
|
|
||||||
|
for (int i=row->fieldCount()-1;i>=0;i--) {
|
||||||
|
EffectField* field = row->field(i);
|
||||||
|
|
||||||
|
if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
|
||||||
|
// sort keyframes by time
|
||||||
|
QVector<int> sorted_keys = sort_keys_from_field(field);
|
||||||
|
|
||||||
|
int last_key_x, last_key_y;
|
||||||
|
|
||||||
|
// draw lines
|
||||||
|
for (int j=0;j<sorted_keys.size();j++) {
|
||||||
|
const EffectKeyframe& key = field->keyframes.at(sorted_keys.at(j));
|
||||||
|
|
||||||
|
int key_x = get_screen_x(key.time);
|
||||||
|
int key_y = get_screen_y(key.data.toDouble());
|
||||||
|
|
||||||
|
line_pen.setColor(get_curve_color(i, row->fieldCount()));
|
||||||
|
p.setPen(line_pen);
|
||||||
|
if (j == 0) {
|
||||||
|
p.drawLine(0, key_y, key_x, key_y);
|
||||||
|
} else {
|
||||||
|
const EffectKeyframe& last_key = field->keyframes.at(sorted_keys.at(j-1));
|
||||||
|
if (last_key.type == KEYFRAME_TYPE_HOLD) {
|
||||||
|
// hold
|
||||||
|
p.drawLine(last_key_x, last_key_y, key_x, last_key_y);
|
||||||
|
p.drawLine(key_x, last_key_y, key_x, key_y);
|
||||||
|
} else if (last_key.type == KEYFRAME_TYPE_BEZIER || key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
|
QPainterPath bezier_path;
|
||||||
|
bezier_path.moveTo(last_key_x, last_key_y);
|
||||||
|
if (last_key.type == KEYFRAME_TYPE_BEZIER && key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
|
// cubic bezier
|
||||||
|
bezier_path.cubicTo(
|
||||||
|
QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom),
|
||||||
|
QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom),
|
||||||
|
QPointF(key_x, key_y)
|
||||||
|
);
|
||||||
|
} else if (key.type == KEYFRAME_TYPE_LINEAR) { // quadratic bezier
|
||||||
|
// last keyframe is the bezier one
|
||||||
|
bezier_path.quadTo(
|
||||||
|
QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom),
|
||||||
|
QPointF(key_x, key_y)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// this keyframe is the bezier one
|
||||||
|
bezier_path.quadTo(
|
||||||
|
QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom),
|
||||||
|
QPointF(key_x, key_y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
p.drawPath(bezier_path);
|
||||||
|
} else {
|
||||||
|
// linear
|
||||||
|
p.drawLine(last_key_x, last_key_y, key_x, key_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_key_x = key_x;
|
||||||
|
last_key_y = key_y;
|
||||||
|
}
|
||||||
|
if (last_key_x < width()) p.drawLine(last_key_x, last_key_y, width(), last_key_y);
|
||||||
|
|
||||||
|
// draw keys
|
||||||
|
for (int j=0;j<sorted_keys.size();j++) {
|
||||||
|
const EffectKeyframe& key = field->keyframes.at(sorted_keys.at(j));
|
||||||
|
|
||||||
|
int key_x = get_screen_x(key.time);
|
||||||
|
int key_y = get_screen_y(key.data.toDouble());
|
||||||
|
|
||||||
|
if (key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
|
p.setPen(Qt::gray);
|
||||||
|
|
||||||
|
// pre handle line
|
||||||
|
QPointF pre_point(key_x + key.pre_handle_x*zoom, key_y - key.pre_handle_y*zoom);
|
||||||
|
p.drawLine(pre_point, QPointF(key_x, key_y));
|
||||||
|
p.drawEllipse(pre_point, BEZIER_HANDLE_SIZE, BEZIER_HANDLE_SIZE);
|
||||||
|
|
||||||
|
// post handle line
|
||||||
|
QPointF post_point(key_x + key.post_handle_x*zoom, key_y - key.post_handle_y*zoom);
|
||||||
|
p.drawLine(post_point, QPointF(key_x, key_y));
|
||||||
|
p.drawEllipse(post_point, BEZIER_HANDLE_SIZE, BEZIER_HANDLE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool selected = false;
|
||||||
|
for (int k=0;k<selected_keys.size();k++) {
|
||||||
|
if (selected_keys.at(k) == sorted_keys.at(j) && selected_keys_fields.at(k) == i) {
|
||||||
|
selected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_keyframe(p, key.type, key_x, key_y, selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw playhead
|
||||||
|
p.setPen(Qt::red);
|
||||||
|
int playhead_x = get_screen_x(panel_sequence_viewer->seq->playhead - visible_in);
|
||||||
|
p.drawLine(playhead_x, 0, playhead_x, height());
|
||||||
|
|
||||||
|
if (rect_select) {
|
||||||
|
draw_selection_rectangle(p, QRect(rect_select_x, rect_select_y, rect_select_w, rect_select_h));
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setPen(Qt::white);
|
||||||
|
|
||||||
|
QRect border = rect();
|
||||||
|
border.setWidth(border.width()-1);
|
||||||
|
border.setHeight(border.height()-1);
|
||||||
|
p.drawRect(border);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::mousePressEvent(QMouseEvent *event) {
|
||||||
|
if (row != NULL) {
|
||||||
|
mousedown = true;
|
||||||
|
start_x = event->pos().x();
|
||||||
|
start_y = event->pos().y();
|
||||||
|
|
||||||
|
// selecting
|
||||||
|
int sel_key = -1;
|
||||||
|
int sel_key_field = -1;
|
||||||
|
current_handle = BEZIER_HANDLE_NONE;
|
||||||
|
|
||||||
|
if (click_add) {
|
||||||
|
selected_keys.clear();
|
||||||
|
selected_keys_fields.clear();
|
||||||
|
|
||||||
|
EffectKeyframe key;
|
||||||
|
key.time = get_value_x(event->pos().x());
|
||||||
|
key.data = get_value_y(event->pos().y());
|
||||||
|
key.type = click_add_type;
|
||||||
|
click_add_key = click_add_field->keyframes.size();
|
||||||
|
click_add_field->keyframes.append(key);
|
||||||
|
update_ui(false);
|
||||||
|
} else {
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
EffectField* field = row->field(i);
|
||||||
|
if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) {
|
||||||
|
for (int j=0;j<field->keyframes.size();j++) {
|
||||||
|
const EffectKeyframe& key = field->keyframes.at(j);
|
||||||
|
int key_x = get_screen_x(key.time);
|
||||||
|
int key_y = get_screen_y(key.data.toDouble());
|
||||||
|
if (event->pos().x() > key_x-KEYFRAME_SIZE
|
||||||
|
&& event->pos().x() < key_x+KEYFRAME_SIZE
|
||||||
|
&& event->pos().y() > key_y-KEYFRAME_SIZE
|
||||||
|
&& event->pos().y() < key_y+KEYFRAME_SIZE) {
|
||||||
|
sel_key = j;
|
||||||
|
sel_key_field = i;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// selecting a handle
|
||||||
|
QPointF pre_point(key_x + key.pre_handle_x*zoom, key_y - key.pre_handle_y*zoom);
|
||||||
|
QPointF post_point(key_x + key.post_handle_x*zoom, key_y - key.post_handle_y*zoom);
|
||||||
|
if (event->pos().x() > pre_point.x()-BEZIER_HANDLE_SIZE
|
||||||
|
&& event->pos().x() < pre_point.x()+BEZIER_HANDLE_SIZE
|
||||||
|
&& event->pos().y() > pre_point.y()-BEZIER_HANDLE_SIZE
|
||||||
|
&& event->pos().y() < pre_point.y()+BEZIER_HANDLE_SIZE) {
|
||||||
|
current_handle = BEZIER_HANDLE_PRE;
|
||||||
|
} else if (event->pos().x() > post_point.x()-BEZIER_HANDLE_SIZE
|
||||||
|
&& event->pos().x() < post_point.x()+BEZIER_HANDLE_SIZE
|
||||||
|
&& event->pos().y() > post_point.y()-BEZIER_HANDLE_SIZE
|
||||||
|
&& event->pos().y() < post_point.y()+BEZIER_HANDLE_SIZE) {
|
||||||
|
current_handle = BEZIER_HANDLE_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_handle != BEZIER_HANDLE_NONE) {
|
||||||
|
sel_key = j;
|
||||||
|
sel_key_field = i;
|
||||||
|
handle_index = j;
|
||||||
|
handle_field = i;
|
||||||
|
old_pre_handle_x = key.pre_handle_x;
|
||||||
|
old_pre_handle_y = key.pre_handle_y;
|
||||||
|
old_post_handle_x = key.post_handle_x;
|
||||||
|
old_post_handle_y = key.post_handle_y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sel_key > -1) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool already_selected = false;
|
||||||
|
if (sel_key > -1) {
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
if (selected_keys.at(i) == sel_key && selected_keys_fields.at(i) == sel_key_field) {
|
||||||
|
if ((event->modifiers() & Qt::ShiftModifier) && current_handle == BEZIER_HANDLE_NONE) {
|
||||||
|
selected_keys.removeAt(i);
|
||||||
|
selected_keys_fields.removeAt(i);
|
||||||
|
}
|
||||||
|
already_selected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!already_selected) {
|
||||||
|
if (!(event->modifiers() & Qt::ShiftModifier)) {
|
||||||
|
selected_keys.clear();
|
||||||
|
selected_keys_fields.clear();
|
||||||
|
}
|
||||||
|
if (sel_key > -1) {
|
||||||
|
selected_keys.append(sel_key);
|
||||||
|
selected_keys_fields.append(sel_key_field);
|
||||||
|
} else {
|
||||||
|
rect_select = true;
|
||||||
|
rect_select_x = event->pos().x();
|
||||||
|
rect_select_y = event->pos().y();
|
||||||
|
rect_select_w = 0;
|
||||||
|
rect_select_h = 0;
|
||||||
|
rect_select_offset = selected_keys.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selection_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::mouseMoveEvent(QMouseEvent *event) {
|
||||||
|
if (!mousedown || !click_add) unsetCursor();
|
||||||
|
if (mousedown) {
|
||||||
|
if (click_add) {
|
||||||
|
click_add_field->keyframes[click_add_key].time = get_value_x(event->pos().x());
|
||||||
|
click_add_field->keyframes[click_add_key].data = get_value_y(event->pos().y());
|
||||||
|
update_ui(false);
|
||||||
|
} else if (event->buttons() & Qt::MiddleButton || panel_timeline->tool == TIMELINE_TOOL_HAND) {
|
||||||
|
set_scroll_x(x_scroll + start_x - event->pos().x());
|
||||||
|
set_scroll_y(y_scroll + event->pos().y() - start_y);
|
||||||
|
start_x = event->pos().x();
|
||||||
|
start_y = event->pos().y();
|
||||||
|
update();
|
||||||
|
} else if (rect_select) {
|
||||||
|
rect_select_w = event->pos().x() - rect_select_x;
|
||||||
|
rect_select_h = event->pos().y() - rect_select_y;
|
||||||
|
|
||||||
|
selected_keys.resize(rect_select_offset);
|
||||||
|
selected_keys_fields.resize(rect_select_offset);
|
||||||
|
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
EffectField* f = row->field(i);
|
||||||
|
for (int j=0;j<f->keyframes.size();j++) {
|
||||||
|
bool already_selected = false;
|
||||||
|
for (int k=0;k<selected_keys.size();k++) {
|
||||||
|
if (selected_keys.at(k) == j && selected_keys_fields.at(k) == i) {
|
||||||
|
already_selected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!already_selected) {
|
||||||
|
QPoint key_screen_point(get_screen_x(f->keyframes.at(j).time), get_screen_y(f->keyframes.at(j).data.toDouble()));
|
||||||
|
QRect select_rect(rect_select_x, rect_select_y, rect_select_w, rect_select_h);
|
||||||
|
if (select_rect.contains(key_screen_point)) {
|
||||||
|
selected_keys.append(j);
|
||||||
|
selected_keys_fields.append(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
switch (current_handle) {
|
||||||
|
case BEZIER_HANDLE_NONE:
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].time = qRound(selected_keys_old_vals.at(i) + (double(event->pos().x() - start_x)/zoom));
|
||||||
|
if (event->modifiers() & Qt::ShiftModifier) {
|
||||||
|
row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = selected_keys_old_doubles.at(i);
|
||||||
|
} else {
|
||||||
|
row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].data = qRound(selected_keys_old_doubles.at(i) + (double(start_y - event->pos().y())/zoom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moved_keys = true;
|
||||||
|
update_ui(false);
|
||||||
|
break;
|
||||||
|
case BEZIER_HANDLE_PRE:
|
||||||
|
case BEZIER_HANDLE_POST:
|
||||||
|
{
|
||||||
|
double new_pre_handle_x = old_pre_handle_x;
|
||||||
|
double new_pre_handle_y = old_pre_handle_y;
|
||||||
|
double new_post_handle_x = old_post_handle_x;
|
||||||
|
double new_post_handle_y = old_post_handle_y;
|
||||||
|
|
||||||
|
double x_diff = double(event->pos().x() - start_x)/zoom;
|
||||||
|
double y_diff = double(start_y - event->pos().y())/zoom;
|
||||||
|
|
||||||
|
if (current_handle == BEZIER_HANDLE_PRE) {
|
||||||
|
new_pre_handle_x += x_diff;
|
||||||
|
if (!(event->modifiers() & Qt::ShiftModifier)) new_pre_handle_y += y_diff;
|
||||||
|
if (!(event->modifiers() & Qt::ControlModifier)) {
|
||||||
|
new_post_handle_x = -new_pre_handle_x;
|
||||||
|
new_post_handle_y = -new_pre_handle_y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_post_handle_x += x_diff;
|
||||||
|
if (!(event->modifiers() & Qt::ShiftModifier)) new_post_handle_y += y_diff;
|
||||||
|
if (!(event->modifiers() & Qt::ControlModifier)) {
|
||||||
|
new_pre_handle_x = -new_post_handle_x;
|
||||||
|
new_pre_handle_y = -new_post_handle_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectKeyframe& key = row->field(handle_field)->keyframes[handle_index];
|
||||||
|
key.pre_handle_x = new_pre_handle_x;
|
||||||
|
key.pre_handle_y = new_pre_handle_y;
|
||||||
|
key.post_handle_x = new_post_handle_x;
|
||||||
|
key.post_handle_y = new_post_handle_y;
|
||||||
|
|
||||||
|
moved_keys = true;
|
||||||
|
update_ui(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (row != NULL) {
|
||||||
|
// clicking on the curve
|
||||||
|
click_add = false;
|
||||||
|
|
||||||
|
bool hovering_key = false;
|
||||||
|
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
for (int j=0;j<row->field(i)->keyframes.size();j++) {
|
||||||
|
const EffectKeyframe& key = row->field(i)->keyframes.at(j);
|
||||||
|
int key_x = get_screen_x(key.time);
|
||||||
|
int key_y = get_screen_y(key.data.toDouble());
|
||||||
|
QRect test_rect(
|
||||||
|
key_x - KEYFRAME_SIZE,
|
||||||
|
key_y - KEYFRAME_SIZE,
|
||||||
|
KEYFRAME_SIZE+KEYFRAME_SIZE,
|
||||||
|
KEYFRAME_SIZE+KEYFRAME_SIZE
|
||||||
|
);
|
||||||
|
QRect pre_rect(
|
||||||
|
qRound(key_x + key.pre_handle_x*zoom - BEZIER_HANDLE_SIZE),
|
||||||
|
qRound(key_y + key.pre_handle_y*zoom - BEZIER_HANDLE_SIZE),
|
||||||
|
BEZIER_HANDLE_SIZE+BEZIER_HANDLE_SIZE,
|
||||||
|
BEZIER_HANDLE_SIZE+BEZIER_HANDLE_SIZE
|
||||||
|
);
|
||||||
|
QRect post_rect(
|
||||||
|
qRound(key_x + key.post_handle_x*zoom - BEZIER_HANDLE_SIZE),
|
||||||
|
qRound(key_y + key.post_handle_y*zoom - BEZIER_HANDLE_SIZE),
|
||||||
|
BEZIER_HANDLE_SIZE+BEZIER_HANDLE_SIZE,
|
||||||
|
BEZIER_HANDLE_SIZE+BEZIER_HANDLE_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (test_rect.contains(event->pos())
|
||||||
|
|| pre_rect.contains(event->pos())
|
||||||
|
|| post_rect.contains(event->pos())) {
|
||||||
|
hovering_key = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hovering_key) {
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
EffectField* f = row->field(i);
|
||||||
|
if (field_visibility.at(i)) {
|
||||||
|
QVector<int> sorted_keys = sort_keys_from_field(f);
|
||||||
|
|
||||||
|
if (event->pos().x() <= get_screen_x(f->keyframes.at(sorted_keys.first()).time)) {
|
||||||
|
int y_comp = get_screen_y(f->keyframes.at(sorted_keys.first()).data.toDouble());
|
||||||
|
if (event->pos().y() >= y_comp-BEZIER_LINE_SIZE
|
||||||
|
&& event->pos().y() <= y_comp+BEZIER_LINE_SIZE) {
|
||||||
|
// dout << "make an EARLY key on field" << i;
|
||||||
|
click_add = true;
|
||||||
|
click_add_type = f->keyframes.at(sorted_keys.first()).type;
|
||||||
|
}
|
||||||
|
} else if (event->pos().x() >= get_screen_x(f->keyframes.at(sorted_keys.last()).time)) {
|
||||||
|
int y_comp = get_screen_y(f->keyframes.at(sorted_keys.last()).data.toDouble());
|
||||||
|
if (event->pos().y() >= y_comp-BEZIER_LINE_SIZE
|
||||||
|
&& event->pos().y() <= y_comp+BEZIER_LINE_SIZE) {
|
||||||
|
// dout << "make an LATE key on field" << i;
|
||||||
|
click_add = true;
|
||||||
|
click_add_type = f->keyframes.at(sorted_keys.last()).type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int j=1;j<sorted_keys.size();j++) {
|
||||||
|
const EffectKeyframe& last_key = f->keyframes.at(sorted_keys.at(j-1));
|
||||||
|
const EffectKeyframe& key = f->keyframes.at(sorted_keys.at(j));
|
||||||
|
|
||||||
|
int last_key_x = get_screen_x(last_key.time);
|
||||||
|
int key_x = get_screen_x(key.time);
|
||||||
|
int last_key_y = get_screen_y(last_key.data.toDouble());
|
||||||
|
int key_y = get_screen_y(key.data.toDouble());
|
||||||
|
|
||||||
|
click_add_type = last_key.type;
|
||||||
|
|
||||||
|
if (event->pos().x() >= last_key_x
|
||||||
|
&& event->pos().x() <= key_x) {
|
||||||
|
QRect mouse_rect(event->pos().x()-BEZIER_LINE_SIZE, event->pos().y()-BEZIER_LINE_SIZE, BEZIER_LINE_SIZE+BEZIER_LINE_SIZE, BEZIER_LINE_SIZE+BEZIER_LINE_SIZE);
|
||||||
|
// NOTE: FILTHY copy/paste from paintEvent
|
||||||
|
if (last_key.type == KEYFRAME_TYPE_HOLD) {
|
||||||
|
// hold
|
||||||
|
if (event->pos().y() >= last_key_y-BEZIER_LINE_SIZE
|
||||||
|
&& event->pos().y() <= last_key_y+BEZIER_LINE_SIZE) {
|
||||||
|
// dout << "make an HOLD key on field" << i << "after key" << j;
|
||||||
|
click_add = true;
|
||||||
|
}
|
||||||
|
} else if (last_key.type == KEYFRAME_TYPE_BEZIER || key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
|
QPainterPath bezier_path;
|
||||||
|
bezier_path.moveTo(last_key_x, last_key_y);
|
||||||
|
if (last_key.type == KEYFRAME_TYPE_BEZIER && key.type == KEYFRAME_TYPE_BEZIER) {
|
||||||
|
// cubic bezier
|
||||||
|
bezier_path.cubicTo(
|
||||||
|
QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom),
|
||||||
|
QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom),
|
||||||
|
QPointF(key_x, key_y)
|
||||||
|
);
|
||||||
|
} else if (key.type == KEYFRAME_TYPE_LINEAR) { // quadratic bezier
|
||||||
|
// last keyframe is the bezier one
|
||||||
|
bezier_path.quadTo(
|
||||||
|
QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom),
|
||||||
|
QPointF(key_x, key_y)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// this keyframe is the bezier one
|
||||||
|
bezier_path.quadTo(
|
||||||
|
QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom),
|
||||||
|
QPointF(key_x, key_y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (bezier_path.intersects(mouse_rect)) {
|
||||||
|
// dout << "make an BEZIER key on field" << i << "after key" << j;
|
||||||
|
click_add = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// linear
|
||||||
|
QPainterPath linear_path;
|
||||||
|
linear_path.moveTo(last_key_x, last_key_y);
|
||||||
|
linear_path.lineTo(key_x, key_y);
|
||||||
|
if (linear_path.intersects(mouse_rect)) {
|
||||||
|
// dout << "make an LINEAR key on field" << i << "after key" << j;
|
||||||
|
click_add = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (click_add) {
|
||||||
|
click_add_field = f;
|
||||||
|
setCursor(Qt::CrossCursor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::mouseReleaseEvent(QMouseEvent *) {
|
||||||
|
if (click_add) {
|
||||||
|
undo_stack.push(new KeyframeFieldSet(click_add_field, click_add_key));
|
||||||
|
} else if (moved_keys && selected_keys.size() > 0) {
|
||||||
|
ComboAction* ca = new ComboAction();
|
||||||
|
switch (current_handle) {
|
||||||
|
case BEZIER_HANDLE_NONE:
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)];
|
||||||
|
ca->append(new SetLong(&key.time, selected_keys_old_vals.at(i), key.time));
|
||||||
|
ca->append(new SetQVariant(&key.data, selected_keys_old_doubles.at(i), key.data));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BEZIER_HANDLE_PRE:
|
||||||
|
case BEZIER_HANDLE_POST:
|
||||||
|
{
|
||||||
|
EffectKeyframe& key = row->field(handle_field)->keyframes[handle_index];
|
||||||
|
ca->append(new SetDouble(&key.pre_handle_x, old_pre_handle_x, key.pre_handle_x));
|
||||||
|
ca->append(new SetDouble(&key.pre_handle_y, old_pre_handle_y, key.pre_handle_y));
|
||||||
|
ca->append(new SetDouble(&key.post_handle_x, old_post_handle_x, key.post_handle_x));
|
||||||
|
ca->append(new SetDouble(&key.post_handle_y, old_post_handle_y, key.post_handle_y));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
undo_stack.push(ca);
|
||||||
|
}
|
||||||
|
moved_keys = false;
|
||||||
|
mousedown = false;
|
||||||
|
click_add = false;
|
||||||
|
if (rect_select) {
|
||||||
|
rect_select = false;
|
||||||
|
selection_update();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::wheelEvent(QWheelEvent *event) {
|
||||||
|
bool redraw = false;
|
||||||
|
bool shift = (event->modifiers() & Qt::ShiftModifier); // scroll instead of zoom
|
||||||
|
|
||||||
|
if (shift) {
|
||||||
|
// scroll
|
||||||
|
set_scroll_x(x_scroll + event->angleDelta().x()/10);
|
||||||
|
set_scroll_y(y_scroll + event->angleDelta().y()/10);
|
||||||
|
redraw = true;
|
||||||
|
} else {
|
||||||
|
// set zoom
|
||||||
|
if (event->angleDelta().y() != 0) {
|
||||||
|
double zoom_diff = (GRAPH_ZOOM_SPEED*zoom);
|
||||||
|
double new_zoom = (event->angleDelta().y() < 0) ? zoom - zoom_diff : zoom + zoom_diff;
|
||||||
|
|
||||||
|
// center zoom on screen
|
||||||
|
set_scroll_x(qRound(x_scroll + double(event->pos().x())*new_zoom - double(event->pos().x())*zoom));
|
||||||
|
set_scroll_y(qRound(y_scroll + double(height()-event->pos().y())*new_zoom - double(height()-event->pos().y())*zoom));
|
||||||
|
|
||||||
|
set_zoom(new_zoom);
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redraw) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_row(EffectRow *r) {
|
||||||
|
if (row != r) {
|
||||||
|
selected_keys.clear();
|
||||||
|
selected_keys_fields.clear();
|
||||||
|
selected_keys_old_vals.clear();
|
||||||
|
selected_keys_old_doubles.clear();
|
||||||
|
emit selection_changed(false, -1);
|
||||||
|
row = r;
|
||||||
|
if (row != NULL) {
|
||||||
|
field_visibility.resize(row->fieldCount());
|
||||||
|
field_visibility.fill(true);
|
||||||
|
visible_in = row->parent_effect->parent_clip->timeline_in;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_selected_keyframe_type(int type) {
|
||||||
|
if (selected_keys.size() > 0) {
|
||||||
|
ComboAction* ca = new ComboAction();
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)];
|
||||||
|
ca->append(new SetInt(&key.type, type));
|
||||||
|
}
|
||||||
|
undo_stack.push(ca);
|
||||||
|
update_ui(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_field_visibility(int field, bool b) {
|
||||||
|
field_visibility[field] = b;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::delete_selected_keys() {
|
||||||
|
if (row != NULL) {
|
||||||
|
QVector<EffectField*> fields;
|
||||||
|
for (int i=0;i<selected_keys_fields.size();i++) {
|
||||||
|
fields.append(row->field(selected_keys_fields.at(i)));
|
||||||
|
}
|
||||||
|
delete_keyframes(fields, selected_keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::select_all() {
|
||||||
|
if (row != NULL) {
|
||||||
|
selected_keys.clear();
|
||||||
|
selected_keys_fields.clear();
|
||||||
|
for (int i=0;i<row->fieldCount();i++) {
|
||||||
|
EffectField* field = row->field(i);
|
||||||
|
for (int j=0;j<field->keyframes.size();j++) {
|
||||||
|
selected_keys.append(j);
|
||||||
|
selected_keys_fields.append(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selection_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_scroll_x(int s) {
|
||||||
|
x_scroll = s;
|
||||||
|
emit x_scroll_changed(x_scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_scroll_y(int s) {
|
||||||
|
y_scroll = s;
|
||||||
|
emit y_scroll_changed(y_scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::set_zoom(double z) {
|
||||||
|
zoom = z;
|
||||||
|
emit zoom_changed(zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GraphView::get_screen_x(double d) {
|
||||||
|
return qRound((d*zoom) - x_scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
int GraphView::get_screen_y(double d) {
|
||||||
|
return qRound(height() + y_scroll - d*zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
long GraphView::get_value_x(int i) {
|
||||||
|
return qRound((i + x_scroll)/zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
double GraphView::get_value_y(int i) {
|
||||||
|
return double(height() + y_scroll - i)/zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphView::selection_update() {
|
||||||
|
selected_keys_old_vals.clear();
|
||||||
|
selected_keys_old_doubles.clear();
|
||||||
|
|
||||||
|
int selected_key_type = -1;
|
||||||
|
|
||||||
|
for (int i=0;i<selected_keys.size();i++) {
|
||||||
|
const EffectKeyframe& key = row->field(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(i));
|
||||||
|
selected_keys_old_vals.append(key.time);
|
||||||
|
selected_keys_old_doubles.append(key.data.toDouble());
|
||||||
|
|
||||||
|
if (selected_key_type == -1) {
|
||||||
|
selected_key_type = key.type;
|
||||||
|
} else if (selected_key_type != key.type) {
|
||||||
|
selected_key_type = -2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
emit selection_changed(selected_keys.size() > 0, selected_key_type);
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#ifndef GRAPHVIEW_H
|
||||||
|
#define GRAPHVIEW_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
class EffectRow;
|
||||||
|
class EffectField;
|
||||||
|
|
||||||
|
QColor get_curve_color(int index, int length);
|
||||||
|
|
||||||
|
class GraphView : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
GraphView(QWidget* parent = 0);
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent *event);
|
||||||
|
void mousePressEvent(QMouseEvent *event);
|
||||||
|
void mouseMoveEvent(QMouseEvent *event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent *event);
|
||||||
|
void wheelEvent(QWheelEvent *event);
|
||||||
|
|
||||||
|
void set_row(EffectRow* r);
|
||||||
|
|
||||||
|
void set_selected_keyframe_type(int type);
|
||||||
|
void set_field_visibility(int field, bool b);
|
||||||
|
|
||||||
|
void delete_selected_keys();
|
||||||
|
void select_all();
|
||||||
|
signals:
|
||||||
|
void x_scroll_changed(int);
|
||||||
|
void y_scroll_changed(int);
|
||||||
|
void zoom_changed(double);
|
||||||
|
void selection_changed(bool, int);
|
||||||
|
private:
|
||||||
|
int x_scroll;
|
||||||
|
int y_scroll;
|
||||||
|
bool mousedown;
|
||||||
|
int start_x;
|
||||||
|
int start_y;
|
||||||
|
double zoom;
|
||||||
|
|
||||||
|
void set_scroll_x(int s);
|
||||||
|
void set_scroll_y(int s);
|
||||||
|
void set_zoom(double z);
|
||||||
|
|
||||||
|
int get_screen_x(double);
|
||||||
|
int get_screen_y(double);
|
||||||
|
long get_value_x(int);
|
||||||
|
double get_value_y(int);
|
||||||
|
|
||||||
|
void selection_update();
|
||||||
|
|
||||||
|
QVector<bool> field_visibility;
|
||||||
|
|
||||||
|
QVector<int> selected_keys;
|
||||||
|
QVector<int> selected_keys_fields;
|
||||||
|
QVector<long> selected_keys_old_vals;
|
||||||
|
QVector<double> selected_keys_old_doubles;
|
||||||
|
|
||||||
|
double old_pre_handle_x;
|
||||||
|
double old_pre_handle_y;
|
||||||
|
double old_post_handle_x;
|
||||||
|
double old_post_handle_y;
|
||||||
|
|
||||||
|
int handle_field;
|
||||||
|
int handle_index;
|
||||||
|
|
||||||
|
bool moved_keys;
|
||||||
|
|
||||||
|
int current_handle;
|
||||||
|
|
||||||
|
void draw_lines(QPainter &p, bool vert);
|
||||||
|
void draw_line_text(QPainter &p, bool vert, int line_no, int line_pos, int next_line_pos);
|
||||||
|
|
||||||
|
EffectRow* row;
|
||||||
|
|
||||||
|
bool rect_select;
|
||||||
|
int rect_select_x;
|
||||||
|
int rect_select_y;
|
||||||
|
int rect_select_w;
|
||||||
|
int rect_select_h;
|
||||||
|
int rect_select_offset;
|
||||||
|
|
||||||
|
long visible_in;
|
||||||
|
|
||||||
|
bool click_add;
|
||||||
|
EffectField* click_add_field;
|
||||||
|
int click_add_key;
|
||||||
|
int click_add_type;
|
||||||
|
private slots:
|
||||||
|
void show_context_menu(const QPoint& pos);
|
||||||
|
void reset_view();
|
||||||
|
void set_view_to_selection();
|
||||||
|
void set_view_to_all();
|
||||||
|
void set_view_to_rect(int x1, double y1, int x2, double y2);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GRAPHVIEW_H
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include "keyframedrawing.h"
|
||||||
|
|
||||||
|
#include "project/effect.h"
|
||||||
|
|
||||||
|
#define KEYFRAME_POINT_COUNT 4
|
||||||
|
|
||||||
|
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r, int g, int b) {
|
||||||
|
if (darker) {
|
||||||
|
r *= 0.625;
|
||||||
|
g *= 0.625;
|
||||||
|
b *= 0.625;
|
||||||
|
}
|
||||||
|
p.setPen(QColor(0, 0, 0));
|
||||||
|
p.setBrush(QColor(r, g, b));
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case KEYFRAME_TYPE_LINEAR:
|
||||||
|
{
|
||||||
|
QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)};
|
||||||
|
p.drawPolygon(points, KEYFRAME_POINT_COUNT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEYFRAME_TYPE_BEZIER:
|
||||||
|
p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE);
|
||||||
|
break;
|
||||||
|
case KEYFRAME_TYPE_HOLD:
|
||||||
|
p.drawRect(QRect(x - KEYFRAME_SIZE, y - KEYFRAME_SIZE, KEYFRAME_SIZE*2, KEYFRAME_SIZE*2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef KEYFRAMEDRAWING_H
|
||||||
|
#define KEYFRAMEDRAWING_H
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#define KEYFRAME_SIZE 6
|
||||||
|
#define KEYFRAME_COLOR 160
|
||||||
|
|
||||||
|
void draw_keyframe(QPainter &p, int type, int x, int y, bool darker, int r = KEYFRAME_COLOR, int g = KEYFRAME_COLOR, int b = KEYFRAME_COLOR);
|
||||||
|
|
||||||
|
#endif // KEYFRAMEDRAWING_H
|
||||||
@@ -2,15 +2,22 @@
|
|||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
|
||||||
KeyframeNavigator::KeyframeNavigator(QWidget *parent) : QWidget(parent) {
|
KeyframeNavigator::KeyframeNavigator(QWidget *parent) : QWidget(parent) {
|
||||||
QSize icon_size(12, 12);
|
int icon_size_val = 8*QApplication::desktop()->devicePixelRatio();
|
||||||
QSize button_size(20, 20);
|
int clock_size_val = 12*QApplication::desktop()->devicePixelRatio();
|
||||||
|
int button_size_val = 20*QApplication::desktop()->devicePixelRatio();
|
||||||
|
|
||||||
|
QSize icon_size(icon_size_val, icon_size_val);
|
||||||
|
QSize clock_size(clock_size_val, clock_size_val);
|
||||||
|
QSize button_size(button_size_val, button_size_val);
|
||||||
|
|
||||||
key_controls = new QHBoxLayout();
|
key_controls = new QHBoxLayout();
|
||||||
key_controls->setSpacing(0);
|
key_controls->setSpacing(0);
|
||||||
key_controls->setMargin(0);
|
key_controls->setMargin(0);
|
||||||
key_controls->addStretch();
|
//key_controls->addStretch();
|
||||||
|
|
||||||
setLayout(key_controls);
|
setLayout(key_controls);
|
||||||
|
|
||||||
@@ -21,6 +28,7 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent) : QWidget(parent) {
|
|||||||
left_key_nav->setVisible(false);
|
left_key_nav->setVisible(false);
|
||||||
key_controls->addWidget(left_key_nav);
|
key_controls->addWidget(left_key_nav);
|
||||||
connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_previous_key()));
|
connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_previous_key()));
|
||||||
|
connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked()));
|
||||||
|
|
||||||
key_addremove = new QPushButton();
|
key_addremove = new QPushButton();
|
||||||
key_addremove->setIcon(QIcon(":/icons/diamond.png"));
|
key_addremove->setIcon(QIcon(":/icons/diamond.png"));
|
||||||
@@ -29,6 +37,7 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent) : QWidget(parent) {
|
|||||||
key_addremove->setVisible(false);
|
key_addremove->setVisible(false);
|
||||||
key_controls->addWidget(key_addremove);
|
key_controls->addWidget(key_addremove);
|
||||||
connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(toggle_key()));
|
connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(toggle_key()));
|
||||||
|
connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(clicked()));
|
||||||
|
|
||||||
right_key_nav = new QPushButton();
|
right_key_nav = new QPushButton();
|
||||||
right_key_nav->setIcon(QIcon(":/icons/tri-right.png"));
|
right_key_nav->setIcon(QIcon(":/icons/tri-right.png"));
|
||||||
@@ -37,20 +46,26 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent) : QWidget(parent) {
|
|||||||
right_key_nav->setVisible(false);
|
right_key_nav->setVisible(false);
|
||||||
key_controls->addWidget(right_key_nav);
|
key_controls->addWidget(right_key_nav);
|
||||||
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_next_key()));
|
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_next_key()));
|
||||||
|
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked()));
|
||||||
|
|
||||||
keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), "");
|
keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), "");
|
||||||
keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
|
keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
|
||||||
keyframe_enable->setMaximumSize(button_size);
|
keyframe_enable->setMaximumSize(button_size);
|
||||||
keyframe_enable->setIconSize(icon_size);
|
keyframe_enable->setIconSize(clock_size);
|
||||||
keyframe_enable->setCheckable(true);
|
keyframe_enable->setCheckable(true);
|
||||||
keyframe_enable->setToolTip("Enable Keyframes");
|
keyframe_enable->setToolTip("Enable Keyframes");
|
||||||
connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(set_keyframe_enabled(bool)));
|
connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(keyframe_enabled_changed(bool)));
|
||||||
connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool)));
|
connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool)));
|
||||||
|
connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(clicked()));
|
||||||
key_controls->addWidget(keyframe_enable);
|
key_controls->addWidget(keyframe_enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeNavigator::enable_keyframes(bool b) {
|
void KeyframeNavigator::enable_keyframes(bool b) {
|
||||||
keyframe_enable->setChecked(b);
|
keyframe_enable->setChecked(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeNavigator::enable_keyframe_toggle(bool b) {
|
||||||
|
keyframe_enable->setVisible(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeNavigator::keyframe_ui_enabled(bool enabled) {
|
void KeyframeNavigator::keyframe_ui_enabled(bool enabled) {
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ class KeyframeNavigator : public QWidget
|
|||||||
public:
|
public:
|
||||||
KeyframeNavigator(QWidget* parent = 0);
|
KeyframeNavigator(QWidget* parent = 0);
|
||||||
void enable_keyframes(bool);
|
void enable_keyframes(bool);
|
||||||
|
void enable_keyframe_toggle(bool);
|
||||||
signals:
|
signals:
|
||||||
void goto_previous_key();
|
void goto_previous_key();
|
||||||
void toggle_key();
|
void toggle_key();
|
||||||
void goto_next_key();
|
void goto_next_key();
|
||||||
void set_keyframe_enabled(bool);
|
void keyframe_enabled_changed(bool);
|
||||||
|
void clicked();
|
||||||
private slots:
|
private slots:
|
||||||
void keyframe_ui_enabled(bool);
|
void keyframe_ui_enabled(bool);
|
||||||
private:
|
private:
|
||||||
|
|||||||
+188
-125
@@ -11,16 +11,18 @@
|
|||||||
#include "panels/viewer.h"
|
#include "panels/viewer.h"
|
||||||
#include "ui/viewerwidget.h"
|
#include "ui/viewerwidget.h"
|
||||||
#include "project/sequence.h"
|
#include "project/sequence.h"
|
||||||
|
#include "panels/grapheditor.h"
|
||||||
|
#include "ui/keyframedrawing.h"
|
||||||
|
#include "ui/clickablelabel.h"
|
||||||
#include "ui/resizablescrollbar.h"
|
#include "ui/resizablescrollbar.h"
|
||||||
|
#include "ui/rectangleselect.h"
|
||||||
|
#include "project/keyframe.h"
|
||||||
|
#include "ui/graphview.h"
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
#define KEYFRAME_SIZE 6
|
|
||||||
#define KEYFRAME_POINT_COUNT 4
|
|
||||||
|
|
||||||
long KeyframeView::adjust_row_keyframe(EffectRow* row, long time) {
|
long KeyframeView::adjust_row_keyframe(EffectRow* row, long time) {
|
||||||
return time-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
|
return time-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
|
||||||
}
|
}
|
||||||
@@ -45,26 +47,36 @@ KeyframeView::KeyframeView(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::show_context_menu(const QPoint& pos) {
|
void KeyframeView::show_context_menu(const QPoint& pos) {
|
||||||
if (selected_rows.size() > 0) {
|
if (selected_fields.size() > 0) {
|
||||||
QMenu menu(this);
|
QMenu menu(this);
|
||||||
|
|
||||||
QAction* linear = menu.addAction("Linear");
|
QAction* linear = menu.addAction("Linear");
|
||||||
linear->setData(KEYFRAME_TYPE_LINEAR);
|
linear->setData(KEYFRAME_TYPE_LINEAR);
|
||||||
QAction* smooth = menu.addAction("Smooth");
|
QAction* bezier = menu.addAction("Bezier");
|
||||||
smooth->setData(KEYFRAME_TYPE_SMOOTH);
|
bezier->setData(KEYFRAME_TYPE_BEZIER);
|
||||||
/*QAction* bezier = menu.addAction("Bezier");
|
QAction* hold = menu.addAction("Hold");
|
||||||
bezier->setData(KEYFRAME_TYPE_BEZIER);*/
|
hold->setData(KEYFRAME_TYPE_HOLD);
|
||||||
|
menu.addSeparator();
|
||||||
|
menu.addAction("Graph Editor");
|
||||||
|
|
||||||
connect(&menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_set_key_type(QAction*)));
|
connect(&menu, SIGNAL(triggered(QAction*)), this, SLOT(menu_set_key_type(QAction*)));
|
||||||
menu.exec(mapToGlobal(pos));
|
menu.exec(mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::menu_set_key_type(QAction* a) {
|
void KeyframeView::menu_set_key_type(QAction* a) {
|
||||||
ComboAction* ca = new ComboAction();
|
if (a->data().isNull()) {
|
||||||
for (int i=0;i<selected_rows.size();i++) {
|
// load graph editor
|
||||||
ca->append(new SetInt(&selected_rows.at(i)->keyframe_types[selected_keyframes.at(i)], a->data().toInt()));
|
panel_graph_editor->show();
|
||||||
|
} else {
|
||||||
|
ComboAction* ca = new ComboAction();
|
||||||
|
for (int i=0;i<selected_fields.size();i++) {
|
||||||
|
EffectField* f = selected_fields.at(i);
|
||||||
|
ca->append(new SetInt(&f->keyframes[selected_keyframes.at(i)].type, a->data().toInt()));
|
||||||
|
}
|
||||||
|
undo_stack.push(ca);
|
||||||
|
update_ui(false);
|
||||||
}
|
}
|
||||||
undo_stack.push(ca);
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::paintEvent(QPaintEvent*) {
|
void KeyframeView::paintEvent(QPaintEvent*) {
|
||||||
@@ -91,15 +103,41 @@ void KeyframeView::paintEvent(QPaintEvent*) {
|
|||||||
for (int j=0;j<e->row_count();j++) {
|
for (int j=0;j<e->row_count();j++) {
|
||||||
EffectRow* row = e->row(j);
|
EffectRow* row = e->row(j);
|
||||||
|
|
||||||
QLabel* label = row->label;
|
ClickableLabel* label = row->label;
|
||||||
QWidget* contents = e->container->contents;
|
QWidget* contents = e->container->contents;
|
||||||
|
|
||||||
|
QVector<long> key_times;
|
||||||
int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height()/* - y_scroll*/;
|
int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height()/* - y_scroll*/;
|
||||||
for (int k=0;k<row->keyframe_times.size();k++) {
|
for (int l=0;l<row->fieldCount();l++) {
|
||||||
bool keyframe_selected = keyframeIsSelected(row, k);
|
EffectField* f = row->field(l);
|
||||||
long keyframe_frame = adjust_row_keyframe(row, row->keyframe_times.at(k));
|
for (int k=0;k<f->keyframes.size();k++) {
|
||||||
if (dragging && keyframe_selected) keyframe_frame += frame_diff;
|
if (!key_times.contains(f->keyframes.at(k).time)) {
|
||||||
draw_keyframe(p, row->keyframe_types.at(k), getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected);
|
bool keyframe_selected = keyframeIsSelected(f, k);
|
||||||
|
long keyframe_frame = adjust_row_keyframe(row, f->keyframes.at(k).time);
|
||||||
|
|
||||||
|
// see if any other keyframes have this time
|
||||||
|
bool solo = true;
|
||||||
|
for (int m=0;m<row->fieldCount();m++) {
|
||||||
|
EffectField* compf = row->field(m);
|
||||||
|
for (int n=0;n<compf->keyframes.size();n++) {
|
||||||
|
if (f->keyframes.at(k).time == compf->keyframes.at(n).time
|
||||||
|
&& !(m == l && k == n)) {
|
||||||
|
solo = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (solo) {
|
||||||
|
QColor cc = get_curve_color(l, row->fieldCount());
|
||||||
|
draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected, cc.red(), cc.green(), cc.blue());
|
||||||
|
} else {
|
||||||
|
draw_keyframe(p, f->keyframes.at(k).type, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame) - x_scroll, keyframe_y, keyframe_selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_times.append(f->keyframes.at(k).time);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.append(row);
|
rows.append(row);
|
||||||
@@ -134,60 +172,32 @@ void KeyframeView::paintEvent(QPaintEvent*) {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeyframeView::keyframeIsSelected(EffectRow *row, int keyframe) {
|
bool KeyframeView::keyframeIsSelected(EffectField *field, int keyframe) {
|
||||||
for (int i=0;i<selected_rows.size();i++) {
|
for (int i=0;i<selected_fields.size();i++) {
|
||||||
if (selected_rows.at(i) == row && selected_keyframes.at(i) == keyframe) {
|
if (selected_fields.at(i) == field && selected_keyframes.at(i) == keyframe) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::delete_selected_keyframes() {
|
void KeyframeView::update_keys() {
|
||||||
KeyframeDelete* kd = new KeyframeDelete();
|
// panel_graph_editor->update_panel();
|
||||||
bool del = false;
|
update();
|
||||||
for (int i=0;i<selected_keyframes.size();i++) {
|
}
|
||||||
selected_rows.at(i)->delete_keyframe(kd, selected_keyframes.at(i));
|
|
||||||
del = true;
|
|
||||||
}
|
|
||||||
if (del) {
|
|
||||||
undo_stack.push(kd);
|
|
||||||
|
|
||||||
selected_keyframes.clear();
|
void KeyframeView::delete_selected_keyframes() {
|
||||||
selected_rows.clear();
|
delete_keyframes(selected_fields, selected_keyframes);
|
||||||
update();
|
|
||||||
panel_sequence_viewer->viewer_widget->update();
|
|
||||||
} else {
|
|
||||||
delete kd;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::set_x_scroll(int s) {
|
void KeyframeView::set_x_scroll(int s) {
|
||||||
x_scroll = s;
|
x_scroll = s;
|
||||||
update();
|
update_keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::set_y_scroll(int s) {
|
void KeyframeView::set_y_scroll(int s) {
|
||||||
y_scroll = s;
|
y_scroll = s;
|
||||||
update();
|
update_keys();
|
||||||
}
|
|
||||||
|
|
||||||
void KeyframeView::draw_keyframe(QPainter &p, int type, int x, int y, bool darker) {
|
|
||||||
int color = (darker) ? 100 : 160;
|
|
||||||
p.setPen(QColor(0, 0, 0));
|
|
||||||
p.setBrush(QColor(color, color, color));
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case KEYFRAME_TYPE_LINEAR:
|
|
||||||
{
|
|
||||||
QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)};
|
|
||||||
p.drawPolygon(points, KEYFRAME_POINT_COUNT);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEYFRAME_TYPE_SMOOTH:
|
|
||||||
p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::resize_move(double d) {
|
void KeyframeView::resize_move(double d) {
|
||||||
@@ -197,15 +207,20 @@ void KeyframeView::resize_move(double d) {
|
|||||||
void KeyframeView::mousePressEvent(QMouseEvent *event) {
|
void KeyframeView::mousePressEvent(QMouseEvent *event) {
|
||||||
rect_select_x = event->x();
|
rect_select_x = event->x();
|
||||||
rect_select_y = event->y();
|
rect_select_y = event->y();
|
||||||
|
rect_select_w = 0;
|
||||||
|
rect_select_h = 0;
|
||||||
|
|
||||||
if (panel_timeline->tool == TIMELINE_TOOL_HAND || event->buttons() & Qt::MiddleButton) {
|
if (panel_timeline->tool == TIMELINE_TOOL_HAND || event->buttons() & Qt::MiddleButton) {
|
||||||
scroll_drag = true;
|
scroll_drag = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_key_vals.clear();
|
||||||
|
|
||||||
int mouse_x = event->x() + x_scroll;
|
int mouse_x = event->x() + x_scroll;
|
||||||
int mouse_y = event->y();
|
int mouse_y = event->y();
|
||||||
int row_index = -1;
|
int row_index = -1;
|
||||||
|
int field_index = -1;
|
||||||
int keyframe_index = -1;
|
int keyframe_index = -1;
|
||||||
long frame_diff = 0;
|
long frame_diff = 0;
|
||||||
long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x-KEYFRAME_SIZE);
|
long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x-KEYFRAME_SIZE);
|
||||||
@@ -214,14 +229,21 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
|
|||||||
for (int i=0;i<rowY.size();i++) {
|
for (int i=0;i<rowY.size();i++) {
|
||||||
if (mouse_y > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) {
|
if (mouse_y > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) {
|
||||||
EffectRow* row = rows.at(i);
|
EffectRow* row = rows.at(i);
|
||||||
for (int j=0;j<row->keyframe_times.size();j++) {
|
|
||||||
long eval_keyframe_time = row->keyframe_times.at(j)-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
|
row->focus_row();
|
||||||
if (eval_keyframe_time >= frame_min && eval_keyframe_time <= frame_max) {
|
|
||||||
long eval_frame_diff = qAbs(eval_keyframe_time - drag_frame_start);
|
for (int k=0;k<row->fieldCount();k++) {
|
||||||
if (keyframe_index == -1 || eval_frame_diff < frame_diff) {
|
EffectField* f = row->field(k);
|
||||||
row_index = i;
|
for (int j=0;j<f->keyframes.size();j++) {
|
||||||
keyframe_index = j;
|
long eval_keyframe_time = f->keyframes.at(j).time-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in);
|
||||||
frame_diff = eval_frame_diff;
|
if (eval_keyframe_time >= frame_min && eval_keyframe_time <= frame_max) {
|
||||||
|
long eval_frame_diff = qAbs(eval_keyframe_time - drag_frame_start);
|
||||||
|
if (keyframe_index == -1 || eval_frame_diff < frame_diff) {
|
||||||
|
row_index = i;
|
||||||
|
field_index = k;
|
||||||
|
keyframe_index = j;
|
||||||
|
frame_diff = eval_frame_diff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,23 +252,46 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) {
|
|||||||
}
|
}
|
||||||
bool already_selected = false;
|
bool already_selected = false;
|
||||||
keys_selected = false;
|
keys_selected = false;
|
||||||
if (keyframe_index > -1) already_selected = keyframeIsSelected(rows.at(row_index), keyframe_index);
|
if (keyframe_index > -1) {
|
||||||
|
already_selected = keyframeIsSelected(rows.at(row_index)->field(field_index), keyframe_index);
|
||||||
|
} else {
|
||||||
|
select_rect = true;
|
||||||
|
}
|
||||||
if (!already_selected) {
|
if (!already_selected) {
|
||||||
if (!(event->modifiers() & Qt::ShiftModifier)) {
|
if (!(event->modifiers() & Qt::ShiftModifier)) {
|
||||||
selected_rows.clear();
|
selected_fields.clear();
|
||||||
selected_keyframes.clear();
|
selected_keyframes.clear();
|
||||||
}
|
}
|
||||||
if (keyframe_index > -1) {
|
if (keyframe_index > -1) {
|
||||||
selected_rows.append(rows.at(row_index));
|
selected_fields.append(rows.at(row_index)->field(field_index));
|
||||||
selected_keyframes.append(keyframe_index);
|
selected_keyframes.append(keyframe_index);
|
||||||
|
|
||||||
|
// find other field with keyframes at the same time
|
||||||
|
long comp_time = rows.at(row_index)->field(field_index)->keyframes.at(keyframe_index).time;
|
||||||
|
for (int i=0;i<rows.at(row_index)->fieldCount();i++) {
|
||||||
|
if (i != field_index) {
|
||||||
|
EffectField* f = rows.at(row_index)->field(i);
|
||||||
|
for (int j=0;j<f->keyframes.size();j++) {
|
||||||
|
if (f->keyframes.at(j).time == comp_time) {
|
||||||
|
selected_fields.append(f);
|
||||||
|
selected_keyframes.append(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected_rows.size() > 0) {
|
if (selected_fields.size() > 0) {
|
||||||
|
for (int i=0;i<selected_fields.size();i++) {
|
||||||
|
old_key_vals.append(selected_fields.at(i)->keyframes.at(selected_keyframes.at(i)).time);
|
||||||
|
}
|
||||||
keys_selected = true;
|
keys_selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
rect_select_offset = selected_fields.size();
|
||||||
|
|
||||||
|
update_keys();
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
mousedown = true;
|
mousedown = true;
|
||||||
@@ -266,46 +311,11 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
|
|||||||
rect_select_y = event->pos().y();
|
rect_select_y = event->pos().y();
|
||||||
} else if (mousedown) {
|
} else if (mousedown) {
|
||||||
int mouse_x = event->x() + x_scroll;
|
int mouse_x = event->x() + x_scroll;
|
||||||
if (keys_selected) {
|
if (select_rect) {
|
||||||
// move keyframes
|
|
||||||
frame_diff = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x) - drag_frame_start;
|
|
||||||
|
|
||||||
// snapping to playhead
|
|
||||||
if (panel_timeline->snapping) {
|
|
||||||
for (int i=0;i<selected_keyframes.size();i++) {
|
|
||||||
EffectRow* row = selected_rows.at(i);
|
|
||||||
Clip* c = row->parent_effect->parent_clip;
|
|
||||||
long key_time = row->keyframe_times.at(selected_keyframes.at(i)) + frame_diff - c->clip_in + c->timeline_in;
|
|
||||||
long key_eval = key_time;
|
|
||||||
if (panel_timeline->snap_to_point(sequence->playhead, &key_eval)) {
|
|
||||||
frame_diff += (key_eval - key_time);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate frame_diff (make sure no keyframes overlap each other)
|
|
||||||
for (int i=0;i<selected_keyframes.size();i++) {
|
|
||||||
EffectRow* row = selected_rows.at(i);
|
|
||||||
long eval_key = row->keyframe_times.at(selected_keyframes.at(i));
|
|
||||||
for (int j=0;j<row->keyframe_times.size();j++) {
|
|
||||||
while (!keyframeIsSelected(row, j) && row->keyframe_times.at(j) == eval_key + frame_diff) {
|
|
||||||
if (last_frame_diff > frame_diff) {
|
|
||||||
frame_diff++;
|
|
||||||
panel_timeline->snapped = false;
|
|
||||||
} else {
|
|
||||||
frame_diff--;
|
|
||||||
panel_timeline->snapped = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_frame_diff = frame_diff;
|
|
||||||
|
|
||||||
dragging = true;
|
|
||||||
} else {
|
|
||||||
// do a rect select
|
// do a rect select
|
||||||
|
selected_fields.resize(rect_select_offset);
|
||||||
|
selected_keyframes.resize(rect_select_offset);
|
||||||
|
|
||||||
rect_select_w = event->x() - rect_select_x;
|
rect_select_w = event->x() - rect_select_x;
|
||||||
rect_select_h = event->y() - rect_select_y;
|
rect_select_h = event->y() - rect_select_y;
|
||||||
|
|
||||||
@@ -320,29 +330,82 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) {
|
|||||||
for (int i=0;i<rowY.size();i++) {
|
for (int i=0;i<rowY.size();i++) {
|
||||||
if (rowY.at(i) >= min_row && rowY.at(i) <= max_row) {
|
if (rowY.at(i) >= min_row && rowY.at(i) <= max_row) {
|
||||||
EffectRow* row = rows.at(i);
|
EffectRow* row = rows.at(i);
|
||||||
for (int j=0;j<row->keyframe_times.size();j++) {
|
for (int k=0;k<row->fieldCount();k++) {
|
||||||
long keyframe_frame = adjust_row_keyframe(row, row->keyframe_times.at(j));
|
EffectField* field = row->field(k);
|
||||||
if (!keyframeIsSelected(row, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) {
|
for (int j=0;j<field->keyframes.size();j++) {
|
||||||
selected_rows.append(rows.at(i));
|
long keyframe_frame = adjust_row_keyframe(row, field->keyframes.at(j).time);
|
||||||
selected_keyframes.append(j);
|
if (!keyframeIsSelected(field, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) {
|
||||||
|
selected_fields.append(field);
|
||||||
|
selected_keyframes.append(j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
select_rect = true;
|
update_keys();
|
||||||
|
} else if (keys_selected) {
|
||||||
|
// move keyframes
|
||||||
|
long frame_diff = getFrameFromScreenPoint(panel_effect_controls->zoom, mouse_x) - drag_frame_start;
|
||||||
|
|
||||||
|
// snapping to playhead
|
||||||
|
panel_timeline->snapped = false;
|
||||||
|
if (panel_timeline->snapping) {
|
||||||
|
for (int i=0;i<selected_keyframes.size();i++) {
|
||||||
|
EffectField* field = selected_fields.at(i);
|
||||||
|
Clip* c = field->parent_row->parent_effect->parent_clip;
|
||||||
|
long key_time = old_key_vals.at(i) + frame_diff - c->clip_in + c->timeline_in;
|
||||||
|
long key_eval = key_time;
|
||||||
|
if (panel_timeline->snap_to_point(sequence->playhead, &key_eval)) {
|
||||||
|
frame_diff += (key_eval - key_time);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate frame_diff (make sure no keyframes overlap each other)
|
||||||
|
for (int i=0;i<selected_fields.size();i++) {
|
||||||
|
EffectField* field = selected_fields.at(i);
|
||||||
|
long eval_key = old_key_vals.at(i);
|
||||||
|
for (int j=0;j<field->keyframes.size();j++) {
|
||||||
|
while (!keyframeIsSelected(field, j) && field->keyframes.at(j).time == eval_key + frame_diff) {
|
||||||
|
if (last_frame_diff > frame_diff) {
|
||||||
|
frame_diff++;
|
||||||
|
panel_timeline->snapped = false;
|
||||||
|
} else {
|
||||||
|
frame_diff--;
|
||||||
|
panel_timeline->snapped = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply frame_diffs
|
||||||
|
for (int i=0;i<selected_keyframes.size();i++) {
|
||||||
|
EffectField* field = selected_fields.at(i);
|
||||||
|
field->keyframes[selected_keyframes.at(i)].time = old_key_vals.at(i) + frame_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_frame_diff = frame_diff;
|
||||||
|
|
||||||
|
dragging = true;
|
||||||
|
|
||||||
|
update_ui(false);
|
||||||
}
|
}
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyframeView::mouseReleaseEvent(QMouseEvent*) {
|
void KeyframeView::mouseReleaseEvent(QMouseEvent*) {
|
||||||
if (dragging && frame_diff != 0) {
|
if (dragging) {
|
||||||
KeyframeMove* ka = new KeyframeMove();
|
ComboAction* ca = new ComboAction();
|
||||||
ka->movement = frame_diff;
|
for (int i=0;i<selected_fields.size();i++) {
|
||||||
ka->keyframes = selected_keyframes;
|
ca->append(new SetLong(
|
||||||
ka->rows = selected_rows;
|
&selected_fields.at(i)->keyframes[selected_keyframes.at(i)].time,
|
||||||
undo_stack.push(ka);
|
old_key_vals.at(i),
|
||||||
|
selected_fields.at(i)->keyframes.at(selected_keyframes.at(i)).time
|
||||||
|
));
|
||||||
|
}
|
||||||
|
undo_stack.push(ca);
|
||||||
}
|
}
|
||||||
|
|
||||||
select_rect = false;
|
select_rect = false;
|
||||||
@@ -350,5 +413,5 @@ void KeyframeView::mouseReleaseEvent(QMouseEvent*) {
|
|||||||
mousedown = false;
|
mousedown = false;
|
||||||
scroll_drag = false;
|
scroll_drag = false;
|
||||||
panel_timeline->snapped = false;
|
panel_timeline->snapped = false;
|
||||||
update();
|
update_ui(false);
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-11
@@ -7,6 +7,7 @@
|
|||||||
struct Clip;
|
struct Clip;
|
||||||
class Effect;
|
class Effect;
|
||||||
class EffectRow;
|
class EffectRow;
|
||||||
|
class EffectField;
|
||||||
class TimelineHeader;
|
class TimelineHeader;
|
||||||
|
|
||||||
class KeyframeView : public QWidget {
|
class KeyframeView : public QWidget {
|
||||||
@@ -23,26 +24,25 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void set_x_scroll(int);
|
void set_x_scroll(int);
|
||||||
void set_y_scroll(int);
|
void set_y_scroll(int);
|
||||||
void resize_move(double d);
|
void resize_move(double d);
|
||||||
private:
|
private:
|
||||||
long adjust_row_keyframe(EffectRow* row, long time);
|
long adjust_row_keyframe(EffectRow* row, long time);
|
||||||
QVector<EffectRow*> selected_rows;
|
QVector<EffectField*> selected_fields;
|
||||||
QVector<int> selected_keyframes;
|
QVector<int> selected_keyframes;
|
||||||
QVector<int> rowY;
|
QVector<int> rowY;
|
||||||
long frame_diff;
|
|
||||||
QVector<EffectRow*> rows;
|
QVector<EffectRow*> rows;
|
||||||
|
QVector<long> old_key_vals;
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
void mouseMoveEvent(QMouseEvent* event);
|
void mouseMoveEvent(QMouseEvent* event);
|
||||||
void mouseReleaseEvent(QMouseEvent *event);
|
void mouseReleaseEvent(QMouseEvent *event);
|
||||||
void paintEvent(QPaintEvent *event);
|
void paintEvent(QPaintEvent *event);
|
||||||
void draw_keyframe(QPainter& p, int type, int x, int y, bool darker);
|
bool mousedown;
|
||||||
bool mousedown;
|
|
||||||
bool dragging;
|
bool dragging;
|
||||||
bool keys_selected;
|
bool keys_selected;
|
||||||
bool select_rect;
|
bool select_rect;
|
||||||
bool scroll_drag;
|
bool scroll_drag;
|
||||||
|
|
||||||
bool keyframeIsSelected(EffectRow* row, int keyframe);
|
bool keyframeIsSelected(EffectField *field, int keyframe);
|
||||||
|
|
||||||
long drag_frame_start;
|
long drag_frame_start;
|
||||||
long last_frame_diff;
|
long last_frame_diff;
|
||||||
@@ -50,12 +50,15 @@ private:
|
|||||||
int rect_select_y;
|
int rect_select_y;
|
||||||
int rect_select_w;
|
int rect_select_w;
|
||||||
int rect_select_h;
|
int rect_select_h;
|
||||||
|
int rect_select_offset;
|
||||||
|
|
||||||
int x_scroll;
|
int x_scroll;
|
||||||
int y_scroll;
|
int y_scroll;
|
||||||
|
|
||||||
|
void update_keys();
|
||||||
private slots:
|
private slots:
|
||||||
void show_context_menu(const QPoint& pos);
|
void show_context_menu(const QPoint& pos);
|
||||||
void menu_set_key_type(QAction*);
|
void menu_set_key_type(QAction*);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEYFRAMEVIEW_H
|
#endif // KEYFRAMEVIEW_H
|
||||||
|
|||||||
+8
-2
@@ -16,7 +16,7 @@ LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) {
|
|||||||
drag_proc = false;
|
drag_proc = false;
|
||||||
min_enabled = false;
|
min_enabled = false;
|
||||||
max_enabled = false;
|
max_enabled = false;
|
||||||
setStyleSheet("QLabel{color:#ffc000;text-decoration:underline;}QLabel:disabled{color:#808080;}");
|
set_color();
|
||||||
setCursor(Qt::SizeHorCursor);
|
setCursor(Qt::SizeHorCursor);
|
||||||
internal_value = -1;
|
internal_value = -1;
|
||||||
set = false;
|
set = false;
|
||||||
@@ -75,7 +75,12 @@ double LabelSlider::getPreviousValue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LabelSlider::set_previous_value() {
|
void LabelSlider::set_previous_value() {
|
||||||
previous_value = internal_value;
|
previous_value = internal_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabelSlider::set_color(QString c) {
|
||||||
|
if (c.isEmpty()) c = "#ffc000";
|
||||||
|
setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}");
|
||||||
}
|
}
|
||||||
|
|
||||||
double LabelSlider::value() {
|
double LabelSlider::value() {
|
||||||
@@ -115,6 +120,7 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) {
|
|||||||
drag_start_x = cursor().pos().x();
|
drag_start_x = cursor().pos().x();
|
||||||
drag_start_y = cursor().pos().y();
|
drag_start_y = cursor().pos().y();
|
||||||
}
|
}
|
||||||
|
emit clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
|
void LabelSlider::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
QString valueToString(double v);
|
QString valueToString(double v);
|
||||||
double getPreviousValue();
|
double getPreviousValue();
|
||||||
void set_previous_value();
|
void set_previous_value();
|
||||||
|
void set_color(QString c = 0);
|
||||||
int decimal_places;
|
int decimal_places;
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QMouseEvent *ev);
|
void mousePressEvent(QMouseEvent *ev);
|
||||||
@@ -53,6 +54,7 @@ private:
|
|||||||
double frame_rate;
|
double frame_rate;
|
||||||
signals:
|
signals:
|
||||||
void valueChanged();
|
void valueChanged();
|
||||||
|
void clicked();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LABELSLIDER_H
|
#endif // LABELSLIDER_H
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "rectangleselect.h"
|
||||||
|
|
||||||
|
void draw_selection_rectangle(QPainter& painter, const QRect& rect) {
|
||||||
|
painter.setPen(QColor(204, 204, 204));
|
||||||
|
painter.setBrush(QColor(0, 0, 0, 32));
|
||||||
|
painter.drawRect(rect);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef RECTANGLESELECT_H
|
||||||
|
#define RECTANGLESELECT_H
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
void draw_selection_rectangle(QPainter& painter, const QRect& rect);
|
||||||
|
|
||||||
|
#endif // RECTANGLESELECT_H
|
||||||
+1
-1
@@ -21,12 +21,12 @@ public:
|
|||||||
bool snapping;
|
bool snapping;
|
||||||
|
|
||||||
void show_text(bool enable);
|
void show_text(bool enable);
|
||||||
void update_zoom(double z);
|
|
||||||
double get_zoom();
|
double get_zoom();
|
||||||
void delete_markers();
|
void delete_markers();
|
||||||
void set_scrollbar_max(QScrollBar* bar, long sequence_end_frame, int offset);
|
void set_scrollbar_max(QScrollBar* bar, long sequence_end_frame, int offset);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void update_zoom(double z);
|
||||||
void set_scroll(int);
|
void set_scroll(int);
|
||||||
void set_visible_in(long i);
|
void set_visible_in(long i);
|
||||||
void show_context_menu(const QPoint &pos);
|
void show_context_menu(const QPoint &pos);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "ui/resizablescrollbar.h"
|
#include "ui/resizablescrollbar.h"
|
||||||
#include "dialogs/newsequencedialog.h"
|
#include "dialogs/newsequencedialog.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "ui/rectangleselect.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#include "project/effect.h"
|
#include "project/effect.h"
|
||||||
|
|||||||
+4
-4
@@ -72,7 +72,7 @@ void ViewerWidget::delete_function() {
|
|||||||
// destroy all textures as well
|
// destroy all textures as well
|
||||||
if (viewer->seq != NULL) {
|
if (viewer->seq != NULL) {
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
closeActiveClips(viewer->seq, true);
|
closeActiveClips(viewer->seq);
|
||||||
doneCurrent();
|
doneCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -485,7 +485,7 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
|||||||
Footage* m = c->media->to_footage();
|
Footage* m = c->media->to_footage();
|
||||||
if (!m->invalid && !(c->track >= 0 && !is_audio_device_set())) {
|
if (!m->invalid && !(c->track >= 0 && !is_audio_device_set())) {
|
||||||
if (m->ready) {
|
if (m->ready) {
|
||||||
const FootageStream* ms = m->get_stream_from_file_index(c->track < 0, c->media_stream);
|
const FootageStream* ms = m->get_stream_from_file_index(c->track < 0, c->media_stream);
|
||||||
if (ms != NULL && is_clip_active(c, playhead)) {
|
if (ms != NULL && is_clip_active(c, playhead)) {
|
||||||
// if thread is already working, we don't want to touch this,
|
// if thread is already working, we don't want to touch this,
|
||||||
// but we also don't want to hang the UI thread
|
// but we also don't want to hang the UI thread
|
||||||
@@ -495,7 +495,7 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
|||||||
clip_is_active = true;
|
clip_is_active = true;
|
||||||
if (c->track >= 0) audio_track_count++;
|
if (c->track >= 0) audio_track_count++;
|
||||||
} else if (c->open) {
|
} else if (c->open) {
|
||||||
close_clip(c);
|
close_clip(c, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//dout << "[WARNING] Media '" + m->name + "' was not ready, retrying...";
|
//dout << "[WARNING] Media '" + m->name + "' was not ready, retrying...";
|
||||||
@@ -507,7 +507,7 @@ GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio)
|
|||||||
if (!c->open) open_clip(c, !rendering);
|
if (!c->open) open_clip(c, !rendering);
|
||||||
clip_is_active = true;
|
clip_is_active = true;
|
||||||
} else if (c->open) {
|
} else if (c->open) {
|
||||||
close_clip(c);
|
close_clip(c, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (clip_is_active) {
|
if (clip_is_active) {
|
||||||
|
|||||||
Reference in New Issue
Block a user