From 170fe9bd0121a5794ef7321a51bf3c02c9567d60 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 12 Mar 2019 19:33:01 +1100 Subject: [PATCH 01/56] decoupled effectfield UI from backend --- dialogs/clippropertiesdialog.cpp | 2 +- dialogs/speeddialog.cpp | 9 +- effects/internal/audionoiseeffect.cpp | 21 +- effects/internal/audionoiseeffect.h | 10 +- effects/internal/cornerpineffect.cpp | 94 +- effects/internal/cornerpineffect.h | 34 +- effects/internal/crossdissolvetransition.cpp | 12 +- effects/internal/cubetransition.cpp | 33 - effects/internal/fillleftrighteffect.cpp | 28 +- effects/internal/fillleftrighteffect.h | 8 +- effects/internal/frei0reffect.cpp | 252 +-- effects/internal/paneffect.cpp | 48 +- effects/internal/paneffect.h | 8 +- effects/internal/shakeeffect.cpp | 86 +- effects/internal/shakeeffect.h | 10 +- effects/internal/solideffect.cpp | 301 ++-- effects/internal/solideffect.h | 24 +- effects/internal/texteffect.cpp | 498 +++--- effects/internal/texteffect.h | 44 +- effects/internal/timecodeeffect.cpp | 79 +- effects/internal/timecodeeffect.h | 18 +- effects/internal/toneeffect.cpp | 66 +- effects/internal/toneeffect.h | 16 +- effects/internal/transformeffect.cpp | 329 ++-- effects/internal/transformeffect.h | 54 +- effects/internal/volumeeffect.cpp | 55 +- effects/internal/volumeeffect.h | 8 +- effects/internal/vsthost.cpp | 5 +- effects/internal/vsthost.h | 54 +- olive.pro | 24 +- panels/grapheditor.cpp | 19 +- panels/viewer.cpp | 2 +- project/clip.cpp | 4 +- project/effect.cpp | 1603 +++++++++--------- project/effect.h | 59 +- project/effectfield.cpp | 489 ------ project/effectfield.h | 108 -- project/effectfields.h | 12 + project/effectfields/boolfield.cpp | 20 + project/effectfields/boolfield.h | 18 + project/effectfields/colorfield.cpp | 22 + project/effectfields/colorfield.h | 18 + project/effectfields/combofield.cpp | 25 + project/effectfields/combofield.h | 29 + project/effectfields/doublefield.cpp | 60 + project/effectfields/doublefield.h | 50 + project/effectfields/effectfield.cpp | 368 ++++ project/effectfields/effectfield.h | 88 + project/effectfields/filefield.cpp | 22 + project/effectfields/filefield.h | 18 + project/effectfields/fontfield.cpp | 22 + project/effectfields/fontfield.h | 17 + project/effectfields/stringfield.cpp | 22 + project/effectfields/stringfield.h | 18 + project/effectgizmo.cpp | 49 +- project/effectgizmo.h | 46 +- project/effectrow.cpp | 399 ++--- project/effectrow.h | 70 +- project/keyframe.cpp | 64 +- project/transition.cpp | 38 +- project/transition.h | 11 +- project/undo.cpp | 22 +- project/undo.h | 4 +- rendering/renderfunctions.cpp | 12 +- ui/graphview.cpp | 10 +- ui/graphview.h | 2 +- ui/keyframeview.cpp | 4 +- ui/labelslider.cpp | 5 +- ui/labelslider.h | 20 +- ui/texteditex.cpp | 64 +- ui/texteditex.h | 30 +- ui/timelinewidget.cpp | 6 +- ui/updatenotification.cpp | 2 +- 73 files changed, 3230 insertions(+), 2971 deletions(-) delete mode 100644 effects/internal/cubetransition.cpp delete mode 100644 project/effectfield.cpp delete mode 100644 project/effectfield.h create mode 100644 project/effectfields.h create mode 100644 project/effectfields/boolfield.cpp create mode 100644 project/effectfields/boolfield.h create mode 100644 project/effectfields/colorfield.cpp create mode 100644 project/effectfields/colorfield.h create mode 100644 project/effectfields/combofield.cpp create mode 100644 project/effectfields/combofield.h create mode 100644 project/effectfields/doublefield.cpp create mode 100644 project/effectfields/doublefield.h create mode 100644 project/effectfields/effectfield.cpp create mode 100644 project/effectfields/effectfield.h create mode 100644 project/effectfields/filefield.cpp create mode 100644 project/effectfields/filefield.h create mode 100644 project/effectfields/fontfield.cpp create mode 100644 project/effectfields/fontfield.h create mode 100644 project/effectfields/stringfield.cpp create mode 100644 project/effectfields/stringfield.h diff --git a/dialogs/clippropertiesdialog.cpp b/dialogs/clippropertiesdialog.cpp index 9d204db02..6f4be32fe 100644 --- a/dialogs/clippropertiesdialog.cpp +++ b/dialogs/clippropertiesdialog.cpp @@ -33,7 +33,7 @@ ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clip layout->addWidget(new QLabel(tr("Duration:")), row, 0); duration_field_ = new LabelSlider(); - duration_field_->set_display_type(LABELSLIDER_FRAMENUMBER); + duration_field_->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); duration_field_->set_minimum_value(1); layout->addWidget(duration_field_, row, 1); diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index 5b0035115..6f38cea38 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -48,7 +48,7 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0); percent = new LabelSlider(this); percent->decimal_places = 2; - percent->set_display_type(LABELSLIDER_PERCENT); + percent->set_display_type(LabelSlider::LABELSLIDER_PERCENT); percent->set_default_value(1); grid->addWidget(percent, 0, 1); @@ -59,7 +59,7 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0); duration = new LabelSlider(this); - duration->set_display_type(LABELSLIDER_FRAMENUMBER); + duration->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); duration->set_frame_rate(olive::ActiveSequence->frame_rate); grid->addWidget(duration, 2, 1); @@ -301,7 +301,10 @@ void SpeedDialog::frame_rate_update() { Clip* c = clips_.at(i); if (c->track() >= 0) { - long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? c->length() : ((c->length() * c->speed().value) / pc_val); + + long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? + c->length() : qRound((c->length() * c->speed().value) / pc_val); + if (len_val > -1 && new_clip_len != len_val) { len_val = -1; break; diff --git a/effects/internal/audionoiseeffect.cpp b/effects/internal/audionoiseeffect.cpp index 26671f253..56b98ca3a 100644 --- a/effects/internal/audionoiseeffect.cpp +++ b/effects/internal/audionoiseeffect.cpp @@ -1,4 +1,4 @@ -/* +/* * Olive. Olive is a free non-linear video editor for Windows, macOS, and Linux. * Copyright (C) 2018 {{ organization }} * @@ -21,14 +21,15 @@ #include AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - amount_val = add_row(tr("Amount"))->add_field(EFFECT_FIELD_DOUBLE, "amount"); - amount_val->set_double_minimum_value(0); - amount_val->set_double_maximum_value(100); - amount_val->set_double_default_value(20); - - mix_val = add_row(tr("Mix"))->add_field(EFFECT_FIELD_BOOL, "mix"); - mix_val->set_bool_value(true); + EffectRow* amount_row = add_row(tr("Amount")); + amount_val = new DoubleField(amount_row, "amount"); + amount_val->SetMinimum(0); + amount_val->SetDefault(20); + amount_val->SetMaximum(100); + EffectRow* mix_row = add_row(tr("Mix")); + mix_val = new BoolField(mix_row, "mix"); + mix_val->SetValueAt(0, true); } void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) { @@ -40,12 +41,12 @@ void AudioNoiseEffect::process_audio(double timecode_start, double timecode_end, qint16 right_noise_sample = this->randomNumber(); // set noise volume - double vol = log_volume( amount_val->get_double_value(timecode, true)*0.01 ); + double vol = log_volume( amount_val->GetDoubleAt(timecode)*0.01 ); left_noise_sample *= vol; right_noise_sample *= vol; // mix with source audio - if (mix_val->get_bool_value(timecode, true)) { + if (mix_val->GetBoolAt(timecode)) { qint16 left_sample = static_cast (((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); qint16 right_sample = static_cast (((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); left_noise_sample = mix_audio_sample(left_noise_sample, left_sample); diff --git a/effects/internal/audionoiseeffect.h b/effects/internal/audionoiseeffect.h index 2906499c9..f2668d354 100644 --- a/effects/internal/audionoiseeffect.h +++ b/effects/internal/audionoiseeffect.h @@ -24,13 +24,13 @@ #include "project/effect.h" class AudioNoiseEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - AudioNoiseEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + AudioNoiseEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* amount_val; - EffectField* mix_val; + DoubleField* amount_val; + BoolField* mix_val; }; #endif // AUDIONOISEEFFECT_H diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index d00ecd571..315ed3f50 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -25,73 +25,73 @@ #include "debug.h" CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - enable_coords = true; - enable_shader = true; + SetFlags(Effect::CoordsFlag & Effect::ShaderFlag); - EffectRow* top_left = add_row(tr("Top Left")); - top_left_x = top_left->add_field(EFFECT_FIELD_DOUBLE, "topleftx"); - top_left_y = top_left->add_field(EFFECT_FIELD_DOUBLE, "toplefty"); + EffectRow* top_left = add_row(tr("Top Left")); + top_left_x = new DoubleField(top_left, "topleftx"); + top_left_y = new DoubleField(top_left, "toplefty"); - EffectRow* top_right = add_row(tr("Top Right")); - top_right_x = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprightx"); - top_right_y = top_right->add_field(EFFECT_FIELD_DOUBLE, "toprighty"); + EffectRow* top_right = add_row(tr("Top Right")); + top_right_x = new DoubleField(top_right, "toprightx"); + top_right_y = new DoubleField(top_right, "toprighty"); - EffectRow* bottom_left = add_row(tr("Bottom Left")); - bottom_left_x = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomleftx"); - bottom_left_y = bottom_left->add_field(EFFECT_FIELD_DOUBLE, "bottomlefty"); + EffectRow* bottom_left = add_row(tr("Bottom Left")); + bottom_left_x = new DoubleField(bottom_left, "bottomleftx"); + bottom_left_y = new DoubleField(bottom_left, "bottomlefty"); - EffectRow* bottom_right = add_row(tr("Bottom Right")); - bottom_right_x = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrightx"); - bottom_right_y = bottom_right->add_field(EFFECT_FIELD_DOUBLE, "bottomrighty"); + EffectRow* bottom_right = add_row(tr("Bottom Right")); + bottom_right_x = new DoubleField(bottom_right, "bottomrightx"); + bottom_right_y = new DoubleField(bottom_right, "bottomrighty"); - perspective = add_row(tr("Perspective"))->add_field(EFFECT_FIELD_BOOL, "perspective"); - perspective->set_bool_value(true); + EffectRow* perspective_row = add_row(tr("Perspective")); + perspective = new BoolField(perspective_row, "perspective"); + perspective->SetValueAt(0, true); - top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_left_gizmo->x_field1 = top_left_x; - top_left_gizmo->y_field1 = top_left_y; + top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_left_gizmo->x_field1 = top_left_x; + top_left_gizmo->y_field1 = top_left_y; - top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->x_field1 = top_right_x; - top_right_gizmo->y_field1 = top_right_y; + top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_right_gizmo->x_field1 = top_right_x; + top_right_gizmo->y_field1 = top_right_y; - bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->x_field1 = bottom_left_x; - bottom_left_gizmo->y_field1 = bottom_left_y; + bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_left_gizmo->x_field1 = bottom_left_x; + bottom_left_gizmo->y_field1 = bottom_left_y; - bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->x_field1 = bottom_right_x; - bottom_right_gizmo->y_field1 = bottom_right_y; + bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_right_gizmo->x_field1 = bottom_right_x; + bottom_right_gizmo->y_field1 = bottom_right_y; - vertPath = "cornerpin.vert"; - fragPath = "cornerpin.frag"; + vertPath = "cornerpin.vert"; + fragPath = "cornerpin.frag"; } void CornerPinEffect::process_coords(double timecode, GLTextureCoords &coords, int) { - coords.vertexTopLeftX += top_left_x->get_double_value(timecode); - coords.vertexTopLeftY += top_left_y->get_double_value(timecode); + coords.vertexTopLeftX += top_left_x->GetDoubleAt(timecode); + coords.vertexTopLeftY += top_left_y->GetDoubleAt(timecode); - coords.vertexTopRightX += top_right_x->get_double_value(timecode); - coords.vertexTopRightY += top_right_y->get_double_value(timecode); + coords.vertexTopRightX += top_right_x->GetDoubleAt(timecode); + coords.vertexTopRightY += top_right_y->GetDoubleAt(timecode); - coords.vertexBottomLeftX += bottom_left_x->get_double_value(timecode); - coords.vertexBottomLeftY += bottom_left_y->get_double_value(timecode); + coords.vertexBottomLeftX += bottom_left_x->GetDoubleAt(timecode); + coords.vertexBottomLeftY += bottom_left_y->GetDoubleAt(timecode); - coords.vertexBottomRightX += bottom_right_x->get_double_value(timecode); - coords.vertexBottomRightY += bottom_right_y->get_double_value(timecode); + coords.vertexBottomRightX += bottom_right_x->GetDoubleAt(timecode); + coords.vertexBottomRightY += bottom_right_y->GetDoubleAt(timecode); } void CornerPinEffect::process_shader(double timecode, GLTextureCoords &coords, int) { - glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY)); - glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY)); - glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY)); - glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY)); - glslProgram->setUniformValue("perspective", perspective->get_bool_value(timecode)); + glslProgram->setUniformValue("p0", GLfloat(coords.vertexBottomLeftX), GLfloat(coords.vertexBottomLeftY)); + glslProgram->setUniformValue("p1", GLfloat(coords.vertexBottomRightX), GLfloat(coords.vertexBottomRightY)); + glslProgram->setUniformValue("p2", GLfloat(coords.vertexTopLeftX), GLfloat(coords.vertexTopLeftY)); + glslProgram->setUniformValue("p3", GLfloat(coords.vertexTopRightX), GLfloat(coords.vertexTopRightY)); + glslProgram->setUniformValue("perspective", perspective->GetBoolAt(timecode)); } void CornerPinEffect::gizmo_draw(double, GLTextureCoords &coords) { - top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); + top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); + bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); + bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); } diff --git a/effects/internal/cornerpineffect.h b/effects/internal/cornerpineffect.h index b1591246d..5b2460ef8 100644 --- a/effects/internal/cornerpineffect.h +++ b/effects/internal/cornerpineffect.h @@ -24,27 +24,27 @@ #include "project/effect.h" class CornerPinEffect : public Effect { - Q_OBJECT + Q_OBJECT public: CornerPinEffect(Clip* c, const EffectMeta* em); - void process_coords(double timecode, GLTextureCoords& coords, int data); - void process_shader(double timecode, GLTextureCoords& coords, int iterations); - void gizmo_draw(double timecode, GLTextureCoords& coords); + void process_coords(double timecode, GLTextureCoords& coords, int data); + void process_shader(double timecode, GLTextureCoords& coords, int iterations); + void gizmo_draw(double timecode, GLTextureCoords& coords); private: - EffectField* top_left_x; - EffectField* top_left_y; - EffectField* top_right_x; - EffectField* top_right_y; - EffectField* bottom_left_x; - EffectField* bottom_left_y; - EffectField* bottom_right_x; - EffectField* bottom_right_y; - EffectField* perspective; + DoubleField* top_left_x; + DoubleField* top_left_y; + DoubleField* top_right_x; + DoubleField* top_right_y; + DoubleField* bottom_left_x; + DoubleField* bottom_left_y; + DoubleField* bottom_right_x; + DoubleField* bottom_right_y; + BoolField* perspective; - EffectGizmo* top_left_gizmo; - EffectGizmo* top_right_gizmo; - EffectGizmo* bottom_left_gizmo; - EffectGizmo* bottom_right_gizmo; + EffectGizmo* top_left_gizmo; + EffectGizmo* top_right_gizmo; + EffectGizmo* bottom_left_gizmo; + EffectGizmo* bottom_right_gizmo; }; #endif // CORNERPINEFFECT_H diff --git a/effects/internal/crossdissolvetransition.cpp b/effects/internal/crossdissolvetransition.cpp index ba495346d..a90fbbeff 100644 --- a/effects/internal/crossdissolvetransition.cpp +++ b/effects/internal/crossdissolvetransition.cpp @@ -23,14 +23,12 @@ #include CrossDissolveTransition::CrossDissolveTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) { - enable_coords = true; - -// add_row("Smooth")->add_field(EFFECT_FIELD_BOOL, "smooth"); + SetFlags(Effect::CoordsFlag); } void CrossDissolveTransition::process_coords(double progress, GLTextureCoords& coords, int data) { - if (!(data == kTransitionClosing && secondary_clip != nullptr)) { - if (data == kTransitionClosing) progress = 1.0 - progress; - coords.opacity *= progress; - } + if (!(data == kTransitionClosing && secondary_clip != nullptr)) { + if (data == kTransitionClosing) progress = 1.0 - progress; + coords.opacity *= progress; + } } diff --git a/effects/internal/cubetransition.cpp b/effects/internal/cubetransition.cpp deleted file mode 100644 index 829ad820d..000000000 --- a/effects/internal/cubetransition.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "cubetransition.h" - -#include "debug.h" - -CubeTransition::CubeTransition(Clip* c, Clip* s, const EffectMeta* em) : Transition(c, s, em) { - enable_coords = true; -} - -void CubeTransition::process_coords(double, GLTextureCoords& coords, int) { - - coords.vertexTopLeftZ = 1; - coords.vertexBottomLeftZ = 1; -} diff --git a/effects/internal/fillleftrighteffect.cpp b/effects/internal/fillleftrighteffect.cpp index e6e687839..d23efa04f 100644 --- a/effects/internal/fillleftrighteffect.cpp +++ b/effects/internal/fillleftrighteffect.cpp @@ -24,21 +24,21 @@ #define FILL_TYPE_RIGHT 1 FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* type_row = add_row(tr("Type")); - fill_type = type_row->add_field(EFFECT_FIELD_COMBO, "type"); - fill_type->add_combo_item(tr("Fill Left with Right"), FILL_TYPE_LEFT); - fill_type->add_combo_item(tr("Fill Right with Left"), FILL_TYPE_RIGHT); + EffectRow* type_row = add_row(tr("Type")); + fill_type = new ComboField(type_row, "type"); + fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT); + fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT); } void FillLeftRightEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { - double interval = (timecode_end-timecode_start)/nb_bytes; - for (int i=0;iget_combo_data(timecode_start+(interval*i)) == FILL_TYPE_LEFT) { - samples[i+1] = samples[i+3]; - samples[i] = samples[i+2]; - } else { - samples[i+3] = samples[i+1]; - samples[i+2] = samples[i]; - } - } + double interval = (timecode_end-timecode_start)/nb_bytes; + for (int i=0;iGetValueAt(timecode_start+(interval*i)) == FILL_TYPE_LEFT) { + samples[i+1] = samples[i+3]; + samples[i] = samples[i+2]; + } else { + samples[i+3] = samples[i+1]; + samples[i+2] = samples[i]; + } + } } diff --git a/effects/internal/fillleftrighteffect.h b/effects/internal/fillleftrighteffect.h index 198f44dcb..6a47a31ac 100644 --- a/effects/internal/fillleftrighteffect.h +++ b/effects/internal/fillleftrighteffect.h @@ -24,12 +24,12 @@ #include "project/effect.h" class FillLeftRightEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - FillLeftRightEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + FillLeftRightEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); private: - EffectField* fill_type; + ComboField* fill_type; }; #endif // FILLLEFTRIGHTEFFECT_H diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp index 223cd0cce..ea0b86f75 100644 --- a/effects/internal/frei0reffect.cpp +++ b/effects/internal/frei0reffect.cpp @@ -31,184 +31,184 @@ typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int heig typedef int (*f0rInitFunc) (); typedef void (*f0rDeinitFunc) (); typedef void (*f0rUpdateFunc) (f0r_instance_t instance, - double time, const uint32_t* inframe, uint32_t* outframe); + double time, const uint32_t* inframe, uint32_t* outframe); typedef void (*f0rDestructFunc)(f0r_instance_t instance); typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info); typedef void (*f0rSetParamValue) (f0r_instance_t instance, - f0r_param_t param, int param_index); + f0r_param_t param, int param_index); Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : - Effect(c, em), - open(false) + Effect(c, em), + open(false) { - enable_image = true; + SetFlags(ImageFlag); - // Windows DLL loading routine - QString dll_fn = QDir(em->path).filePath(em->filename); + // Windows DLL loading routine + QString dll_fn = QDir(em->path).filePath(em->filename); - handle = LibLoad(dll_fn); - if(handle == nullptr) { - QString dll_error; + handle = LibLoad(dll_fn); + if(handle == nullptr) { + QString dll_error; #ifdef _WIN32 - DWORD dll_err = GetLastError(); - dll_error = QString::number(dll_err); + DWORD dll_err = GetLastError(); + dll_error = QString::number(dll_err); #elif __linux__ - dll_error = dlerror(); + dll_error = dlerror(); #endif - qCritical() << "Failed to load Frei0r plugin" << dll_fn << "-" << dll_error; + qCritical() << "Failed to load Frei0r plugin" << dll_fn << "-" << dll_error; - QString msg_err = tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error); + QString msg_err = tr("Failed to load Frei0r plugin \"%1\": %2").arg(dll_fn, dll_error); #ifdef _WIN32 - if (dll_err == 193) { + if (dll_err == 193) { #ifdef _WIN64 - msg_err += "\n\n" + tr("NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); + msg_err += "\n\n" + tr("NOTE: You can't load 32-bit Frei0r plugins into a 64-bit build of Olive. Please find a 64-bit version of this plugin or switch to a 32-bit build of Olive."); #elif _WIN32 - msg_err += "\n\n" + tr("NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); + msg_err += "\n\n" + tr("NOTE: You can't load 64-bit Frei0r plugins into a 32-bit build of Olive. Please find a 32-bit version of this plugin or switch to a 64-bit build of Olive."); #endif - } + } #endif - QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"), msg_err); + QMessageBox::critical(nullptr, tr("Error loading Frei0r plugin"), msg_err); - return; - } + return; + } - f0rInitFunc init = reinterpret_cast(LibAddress(handle, "f0r_init")); - init(); + f0rInitFunc init = reinterpret_cast(LibAddress(handle, "f0r_init")); + init(); - construct_module(); + construct_module(); - f0r_plugin_info_t info; - f0rGetPluginInfo info_func = reinterpret_cast(LibAddress(handle, "f0r_get_plugin_info")); - info_func(&info); + f0r_plugin_info_t info; + f0rGetPluginInfo info_func = reinterpret_cast(LibAddress(handle, "f0r_get_plugin_info")); + info_func(&info); - param_count = info.num_params; + param_count = info.num_params; - get_param_info = reinterpret_cast(LibAddress(handle, "f0r_get_param_info")); - for (int i=0;i(LibAddress(handle, "f0r_get_param_info")); + for (int i=0;i= 0 && param_info.type <= F0R_PARAM_STRING) { - EffectRow* row = add_row(param_info.name); - switch (param_info.type) { - case F0R_PARAM_BOOL: - row->add_field(EFFECT_FIELD_BOOL, QString::number(i)); - break; - case F0R_PARAM_DOUBLE: - { - EffectField* f = row->add_field(EFFECT_FIELD_DOUBLE, QString::number(i)); - f->set_double_minimum_value(0); - f->set_double_maximum_value(100); - } - break; - case F0R_PARAM_COLOR: - row->add_field(EFFECT_FIELD_COLOR, QString::number(i)); - break; - case F0R_PARAM_POSITION: - { - EffectField* fx = row->add_field(EFFECT_FIELD_DOUBLE, QString("%1X").arg(QString::number(i))); - fx->set_double_minimum_value(0); - fx->set_double_maximum_value(100); - EffectField* fy = row->add_field(EFFECT_FIELD_DOUBLE, QString("%1Y").arg(QString::number(i))); - fy->set_double_minimum_value(0); - fy->set_double_maximum_value(100); - } - break; - case F0R_PARAM_STRING: - row->add_field(EFFECT_FIELD_STRING, QString::number(i)); - break; - } - } - } + if (param_info.type >= 0 && param_info.type <= F0R_PARAM_STRING) { + EffectRow* row = add_row(param_info.name); + switch (param_info.type) { + case F0R_PARAM_BOOL: + new BoolField(row, QString::number(i)); + break; + case F0R_PARAM_DOUBLE: + { + DoubleField* f = new DoubleField(row, QString::number(i)); + f->SetMinimum(0); + f->SetMaximum(100); + } + break; + case F0R_PARAM_COLOR: + new ColorField(row, QString::number(i)); + break; + case F0R_PARAM_POSITION: + { + DoubleField* fx = new DoubleField(row, QString("%1X").arg(QString::number(i))); + fx->SetMinimum(0); + fx->SetMaximum(100); + DoubleField* fy = new DoubleField(row, QString("%1Y").arg(QString::number(i))); + fy->SetMinimum(0); + fy->SetMaximum(100); + } + break; + case F0R_PARAM_STRING: + new StringField(row, QString::number(i)); + break; + } + } + } } Frei0rEffect::~Frei0rEffect() { - if (handle != nullptr) { - f0rDeinitFunc deinit = reinterpret_cast(LibAddress(handle, "f0r_deinit")); - deinit(); + if (handle != nullptr) { + f0rDeinitFunc deinit = reinterpret_cast(LibAddress(handle, "f0r_deinit")); + deinit(); - LibClose(handle); - } + LibClose(handle); + } } void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *output, int) { - f0rUpdateFunc update_func = reinterpret_cast(LibAddress(handle, "f0r_update")); + f0rUpdateFunc update_func = reinterpret_cast(LibAddress(handle, "f0r_update")); - for (int i=0;i(LibAddress(handle, "f0r_set_param_value")); - switch (param_info.type) { - case F0R_PARAM_BOOL: - { - double b = param_row->field(0)->get_bool_value(timecode); - set_param(instance, &b, i); - } - break; - case F0R_PARAM_DOUBLE: - { - double d = param_row->field(0)->get_double_value(timecode)*0.01; - set_param(instance, &d, i); - } - break; - case F0R_PARAM_COLOR: - { - QColor qcolor = param_row->field(0)->get_color_value(timecode);; + f0rSetParamValue set_param = reinterpret_cast(LibAddress(handle, "f0r_set_param_value")); + switch (param_info.type) { + case F0R_PARAM_BOOL: + { + double b = param_row->field(0)->GetValueAt(timecode).toBool(); + set_param(instance, &b, i); + } + break; + case F0R_PARAM_DOUBLE: + { + double d = param_row->field(0)->GetValueAt(timecode).toDouble()*0.01; + set_param(instance, &d, i); + } + break; + case F0R_PARAM_COLOR: + { + QColor qcolor = param_row->field(0)->GetValueAt(timecode).value(); - f0r_param_color fcolor; - fcolor.r = float(qcolor.redF()); - fcolor.g = float(qcolor.greenF()); - fcolor.b = float(qcolor.blueF()); + f0r_param_color fcolor; + fcolor.r = float(qcolor.redF()); + fcolor.g = float(qcolor.greenF()); + fcolor.b = float(qcolor.blueF()); - set_param(instance, &fcolor, i); - } - break; - case F0R_PARAM_POSITION: - { - f0r_param_position pos; - pos.x = param_row->field(0)->get_double_value(timecode); - pos.y = param_row->field(1)->get_double_value(timecode); - set_param(instance, &pos, i); - } - break; - case F0R_PARAM_STRING: - { - QByteArray bytes = param_row->field(0)->get_string_value(timecode).toUtf8(); - char* byte_data = bytes.data(); - set_param(instance, &byte_data, i); - } - break; - } - } + set_param(instance, &fcolor, i); + } + break; + case F0R_PARAM_POSITION: + { + f0r_param_position pos; + pos.x = param_row->field(0)->GetValueAt(timecode).toDouble(); + pos.y = param_row->field(1)->GetValueAt(timecode).toDouble(); + set_param(instance, &pos, i); + } + break; + case F0R_PARAM_STRING: + { + QByteArray bytes = param_row->field(0)->GetValueAt(timecode).toString().toUtf8(); + char* byte_data = bytes.data(); + set_param(instance, &byte_data, i); + } + break; + } + } - update_func(instance, timecode, reinterpret_cast(input), reinterpret_cast(output)); + update_func(instance, timecode, reinterpret_cast(input), reinterpret_cast(output)); } void Frei0rEffect::refresh() { - destruct_module(); - construct_module(); + destruct_module(); + construct_module(); } void Frei0rEffect::destruct_module() { - if (open) { - f0rDestructFunc destruct = reinterpret_cast(LibAddress(handle, "f0r_destruct")); - destruct(instance); + if (open) { + f0rDestructFunc destruct = reinterpret_cast(LibAddress(handle, "f0r_destruct")); + destruct(instance); - open = false; - } + open = false; + } } void Frei0rEffect::construct_module() { - f0rConstructFunc construct = reinterpret_cast(LibAddress(handle, "f0r_construct")); + f0rConstructFunc construct = reinterpret_cast(LibAddress(handle, "f0r_construct")); instance = construct(parent_clip->media_width(), parent_clip->media_height()); - open = true; + open = true; } #endif diff --git a/effects/internal/paneffect.cpp b/effects/internal/paneffect.cpp index babb0b01b..7ebb3af8e 100644 --- a/effects/internal/paneffect.cpp +++ b/effects/internal/paneffect.cpp @@ -29,35 +29,33 @@ #include "ui/collapsiblewidget.h" PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* pan_row = add_row(tr("Pan")); - pan_val = pan_row->add_field(EFFECT_FIELD_DOUBLE, "pan"); - pan_val->set_double_minimum_value(-100); - pan_val->set_double_maximum_value(100); - - // set defaults - pan_val->set_double_default_value(0); + EffectRow* pan_row = add_row(tr("Pan")); + pan_val = new DoubleField(pan_row, "pan"); + pan_val->SetMinimum(-100); + pan_val->SetDefault(0); + pan_val->SetMaximum(100); } void PanEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { - double interval = (timecode_end - timecode_start)/nb_bytes; - for (int i=0;iget_double_value(timecode_start+(interval*i), true); - double pval = log_volume(qAbs(pan_field_val)*0.01); + double interval = (timecode_end - timecode_start)/nb_bytes; + for (int i=0;iGetDoubleAt(timecode_start+(interval*i)); + double pval = log_volume(qAbs(pan_field_val)*0.01); - qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); - qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - if (pan_field_val < 0) { - // affect right channel - right_sample *= (1.0-pval); - } else { - // affect left channel - left_sample *= (1.0-pval); - } + if (pan_field_val < 0) { + // affect right channel + right_sample *= (1.0-pval); + } else { + // affect left channel + left_sample *= (1.0-pval); + } - samples[i+3] = quint8(right_sample >> 8); - samples[i+2] = quint8(right_sample); - samples[i+1] = quint8(left_sample >> 8); - samples[i] = quint8(left_sample); - } + samples[i+3] = quint8(right_sample >> 8); + samples[i+2] = quint8(right_sample); + samples[i+1] = quint8(left_sample >> 8); + samples[i] = quint8(left_sample); + } } diff --git a/effects/internal/paneffect.h b/effects/internal/paneffect.h index 7640c48be..aab759b54 100644 --- a/effects/internal/paneffect.h +++ b/effects/internal/paneffect.h @@ -24,12 +24,12 @@ #include "project/effect.h" class PanEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - PanEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + PanEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* pan_val; + DoubleField* pan_val; }; #endif // PANEFFECT_H diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index a8d5f53f7..e27cb912a 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -34,62 +34,60 @@ #include "debug.h" ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - enable_coords = true; + SetFlags(Effect::CoordsFlag); - EffectRow* intensity_row = add_row(tr("Intensity")); - intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE, "intensity"); - intensity_val->set_double_minimum_value(0); + EffectRow* intensity_row = add_row(tr("Intensity")); + intensity_val = new DoubleField(intensity_row, "intensity"); + intensity_val->SetMinimum(0); + intensity_val->SetDefault(25); - EffectRow* rotation_row = add_row(tr("Rotation")); - rotation_val = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation"); - rotation_val->set_double_minimum_value(0); + EffectRow* rotation_row = add_row(tr("Rotation")); + rotation_val = new DoubleField(rotation_row, "rotation"); + rotation_val->SetMinimum(0); + rotation_val->SetDefault(10); - EffectRow* frequency_row = add_row(tr("Frequency")); - frequency_val = frequency_row->add_field(EFFECT_FIELD_DOUBLE, "frequency"); - frequency_val->set_double_minimum_value(0); + EffectRow* frequency_row = add_row(tr("Frequency")); + frequency_val = new DoubleField(frequency_row, "frequency"); + frequency_val->SetMinimum(0); + frequency_val->SetDefault(5); - // set defaults - intensity_val->set_double_default_value(25); - rotation_val->set_double_default_value(10); - frequency_val->set_double_default_value(5); - - const auto limit = std::numeric_limits::max(); - for (int i=0;i(this->randomNumber()) / limit; - } + const auto limit = std::numeric_limits::max(); + for (int i=0;i(this->randomNumber()) / limit; + } } void ShakeEffect::process_coords(double timecode, GLTextureCoords& coords, int) { - int lim = RANDOM_VAL_SIZE/6; + int lim = RANDOM_VAL_SIZE/6; - double multiplier = intensity_val->get_double_value(timecode)/lim; - double rotmult = rotation_val->get_double_value(timecode)/lim/10; - double x = timecode * frequency_val->get_double_value(timecode); + double multiplier = intensity_val->GetDoubleAt(timecode)/lim; + double rotmult = rotation_val->GetDoubleAt(timecode)/lim/10; + double x = timecode * frequency_val->GetDoubleAt(timecode); - double xoff = 0; - double yoff = 0; - double rotoff = 0; + double xoff = 0; + double yoff = 0; + double rotoff = 0; - for (int i=0;iAddItem(tr("Solid Color"), SOLID_TYPE_COLOR); + solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS); + solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); - solid_type = add_row(tr("Type"))->add_field(EFFECT_FIELD_COMBO, "type"); - solid_type->add_combo_item(tr("Solid Color"), SOLID_TYPE_COLOR); - solid_type->add_combo_item(tr("SMPTE Bars"), SOLID_TYPE_BARS); - solid_type->add_combo_item(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); + EffectRow* opacity_row = add_row(tr("Opacity")); + opacity_field = new DoubleField(opacity_row, "opacity"); + opacity_field->SetMinimum(0); + opacity_field->SetDefault(0); + opacity_field->SetMaximum(100); - opacity_field = add_row(tr("Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "opacity"); - opacity_field->set_double_minimum_value(0); - opacity_field->set_double_maximum_value(100); - opacity_field->set_double_default_value(100); + EffectRow* solid_color_row = add_row(tr("Color")); + solid_color_field = new ColorField(solid_color_row, "color"); + solid_color_field->SetValueAt(0, QColor(Qt::red)); - solid_color_field = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color"); - solid_color_field->set_color_value(Qt::red); + EffectRow* checkerboard_size = add_row(tr("Checkerboard Size")); + checkerboard_size_field = new DoubleField(checkerboard_size, "checker_size"); + checkerboard_size_field->SetMinimum(1); + checkerboard_size_field->SetDefault(10); - checkerboard_size_field = add_row(tr("Checkerboard Size"))->add_field(EFFECT_FIELD_DOUBLE, "checker_size"); - checkerboard_size_field->set_double_minimum_value(1); - checkerboard_size_field->set_double_default_value(10); + connect(solid_type, SIGNAL(IndexChanged(int)), this, SLOT(ui_update(int))); - // hacky but eh - QComboBox* solid_type_combo = static_cast(solid_type->get_ui_element()); - connect(solid_type_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(ui_update(int))); - ui_update(solid_type_combo->currentIndex()); + // Set default UI + solid_type->SetValueAt(0, SOLID_TYPE_COLOR); - /*vertPath = ":/shaders/common.vert"; - fragPath = ":/shaders/solideffect.frag";*/ + // TODO necessary? Isn't this called from the connect() above? + ui_update(SOLID_TYPE_COLOR); + + /*vertPath = ":/shaders/common.vert"; + fragPath = ":/shaders/solideffect.frag";*/ } void SolidEffect::redraw(double timecode) { - int w = img.width(); - int h = img.height(); - int alpha = qRound(opacity_field->get_double_value(timecode)*2.55); - switch (solid_type->get_combo_data(timecode).toInt()) { - case SOLID_TYPE_COLOR: - { - QColor solidColor = solid_color_field->get_color_value(timecode); - solidColor.setAlpha(alpha); - img.fill(solidColor); - } - break; - case SOLID_TYPE_BARS: - { - // draw smpte bars - QPainter p(&img); - img.fill(Qt::transparent); - int bar_width = qCeil((double) w / 7.0); - int first_bar_height = qCeil((double) h / 3.0 * 2.0); - int second_bar_height = qCeil((double) h / 12.5); - int third_bar_y = first_bar_height + second_bar_height; - int third_bar_height = h - third_bar_y; - int third_bar_width = 0; - int bar_x, strip_width; - QColor first_color, second_color, third_color; - for (int i=0;iGetDoubleAt(timecode)*2.55); + switch (solid_type->GetValueAt(timecode).toInt()) { + case SOLID_TYPE_COLOR: + { + QColor solidColor = solid_color_field->GetColorAt(timecode); + solidColor.setAlpha(alpha); + img.fill(solidColor); + } + break; + case SOLID_TYPE_BARS: + { + // draw smpte bars + QPainter p(&img); + img.fill(Qt::transparent); + int bar_width = qCeil(double(w) / 7.0); + int first_bar_height = qCeil(double(h) / 3.0 * 2.0); + int second_bar_height = qCeil(double(h) / 12.5); + int third_bar_y = first_bar_height + second_bar_height; + int third_bar_height = h - third_bar_y; + int third_bar_width = 0; + int bar_x, strip_width; + QColor first_color, second_color, third_color; + for (int i=0;iget_double_value(timecode)); - int checker_x, checker_y; - int checkerboard_size_w = qCeil(double(w)/checker_width); - int checkerboard_size_h = qCeil(double(h)/checker_width); + int checker_width = qCeil(checkerboard_size_field->GetDoubleAt(timecode)); + int checker_x, checker_y; + int checkerboard_size_w = qCeil(double(w)/checker_width); + int checkerboard_size_h = qCeil(double(h)/checker_width); - QColor checker_odd(QColor(0, 0, 0, alpha)); - QColor checker_even(solid_color_field->get_color_value(timecode)); - checker_even.setAlpha(alpha); - QVector checker_color{checker_odd, checker_even}; + QColor checker_odd(QColor(0, 0, 0, alpha)); + QColor checker_even(solid_color_field->GetColorAt(timecode)); + checker_even.setAlpha(alpha); + QVector checker_color{checker_odd, checker_even}; - for(int i = 0; i < checkerboard_size_w; i++){ - checker_x = checker_width*i; - for(int j = 0; j < checkerboard_size_h; j++){ - checker_y = checker_width*j; - p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]); - } - } - } - break; - } + for(int i = 0; i < checkerboard_size_w; i++){ + checker_x = checker_width*i; + for(int j = 0; j < checkerboard_size_h; j++){ + checker_y = checker_width*j; + p.fillRect(QRect(checker_x, checker_y, checker_width, checker_width), checker_color[(i + j)%2]); + } + } + } + break; + } +} + +void SolidEffect::SetType(SolidEffect::SolidType type) +{ + solid_type->SetValueAt(0, type); } void SolidEffect::ui_update(int i) { - solid_color_field->set_enabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD); - checkerboard_size_field->set_enabled(i == SOLID_TYPE_CHECKERBOARD); + solid_color_field->SetEnabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD); + checkerboard_size_field->SetEnabled(i == SOLID_TYPE_CHECKERBOARD); } diff --git a/effects/internal/solideffect.h b/effects/internal/solideffect.h index 9175e02e6..0b5b22846 100644 --- a/effects/internal/solideffect.h +++ b/effects/internal/solideffect.h @@ -26,17 +26,25 @@ #include class SolidEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - SolidEffect(Clip* c, const EffectMeta *em); - void redraw(double timecode); + enum SolidType { + SOLID_TYPE_COLOR, + SOLID_TYPE_BARS, + SOLID_TYPE_CHECKERBOARD + }; + + SolidEffect(Clip* c, const EffectMeta *em); + virtual void redraw(double timecode); + + void SetType(SolidType type); private slots: - void ui_update(int); + void ui_update(int); private: - EffectField* solid_type; - EffectField* solid_color_field; - EffectField* opacity_field; - EffectField* checkerboard_size_field; + ComboField* solid_type; + ColorField* solid_color_field; + DoubleField* opacity_field; + DoubleField* checkerboard_size_field; }; #endif // SOLIDEFFECT_H diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index bb3b5de41..f3fecf396 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -40,314 +40,326 @@ #include "ui/comboboxex.h" #include "ui/colorbutton.h" #include "ui/fontcombobox.h" -#include "dialogs/texteditdialog.h" #include "io/config.h" -#include "mainwindow.h" TextEffect::TextEffect(Clip* c, const EffectMeta* em) : - Effect(c, em) + Effect(c, em) { - enable_superimpose = true; + SetFlags(Effect::SuperimposeFlag); - text_val = add_row(tr("Text"))->add_field(EFFECT_FIELD_STRING, "text", 2); - QTextEdit* text_widget = static_cast(text_val->ui_element); - text_widget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(text_widget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); + EffectRow* text_field = add_row(tr("Text")); + text_val = new StringField(text_field, "text"); + text_val->SetColumnSpan(2); - set_font_combobox = add_row(tr("Font"))->add_field(EFFECT_FIELD_FONT, "font", 2); + EffectRow* font_row = add_row(tr("Font")); + set_font_combobox = new FontField(font_row, "font"); + set_font_combobox->SetColumnSpan(2); - size_val = add_row(tr("Size"))->add_field(EFFECT_FIELD_DOUBLE, "size", 2); - size_val->set_double_minimum_value(0); + EffectRow* size_row = add_row(tr("Size")); + size_val = new DoubleField(size_row, "size"); + size_val->SetMinimum(0); + size_val->SetColumnSpan(2); - set_color_button = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2); + EffectRow* color_row = add_row(tr("Color")); + set_color_button = new ColorField(color_row, "color"); + set_color_button->SetColumnSpan(2); - EffectRow* alignment_row = add_row(tr("Alignment")); - halign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "halign"); - halign_field->add_combo_item(tr("Left"), Qt::AlignLeft); - halign_field->add_combo_item(tr("Center"), Qt::AlignHCenter); - halign_field->add_combo_item(tr("Right"), Qt::AlignRight); - halign_field->add_combo_item(tr("Justify"), Qt::AlignJustify); + EffectRow* alignment_row = add_row(tr("Alignment")); + halign_field = new ComboField(alignment_row, "halign"); + halign_field->AddItem(tr("Left"), Qt::AlignLeft); + halign_field->AddItem(tr("Center"), Qt::AlignHCenter); + halign_field->AddItem(tr("Right"), Qt::AlignRight); + halign_field->AddItem(tr("Justify"), Qt::AlignJustify); - valign_field = alignment_row->add_field(EFFECT_FIELD_COMBO, "valign"); - valign_field->add_combo_item(tr("Top"), Qt::AlignTop); - valign_field->add_combo_item(tr("Center"), Qt::AlignVCenter); - valign_field->add_combo_item(tr("Bottom"), Qt::AlignBottom); + valign_field = new ComboField(alignment_row, "valign"); + valign_field->AddItem(tr("Top"), Qt::AlignTop); + valign_field->AddItem(tr("Center"), Qt::AlignVCenter); + valign_field->AddItem(tr("Bottom"), Qt::AlignBottom); - word_wrap_field = add_row(tr("Word Wrap"))->add_field(EFFECT_FIELD_BOOL, "wordwrap", 2); + EffectRow* word_wrap_row = add_row(tr("Word Wrap")); + word_wrap_field = new BoolField(word_wrap_row, "wordwrap"); + word_wrap_field->SetColumnSpan(2); - outline_bool = add_row(tr("Outline"))->add_field(EFFECT_FIELD_BOOL, "outline", 2); - outline_color = add_row(tr("Outline Color"))->add_field(EFFECT_FIELD_COLOR, "outlinecolor", 2); - outline_width = add_row(tr("Outline Width"))->add_field(EFFECT_FIELD_DOUBLE, "outlinewidth", 2); - outline_width->set_double_minimum_value(0); + EffectRow* outline_row = add_row(tr("Outline")); + outline_bool = new BoolField(outline_row, "outline"); + outline_bool->SetColumnSpan(2); - shadow_bool = add_row(tr("Shadow"))->add_field(EFFECT_FIELD_BOOL, "shadow", 2); - shadow_color = add_row(tr("Shadow Color"))->add_field(EFFECT_FIELD_COLOR, "shadowcolor", 2); - shadow_angle = add_row(tr("Shadow Angle"))->add_field(EFFECT_FIELD_DOUBLE, "shadowangle", 2); - shadow_distance = add_row(tr("Shadow Distance"))->add_field(EFFECT_FIELD_DOUBLE, "shadowdistance", 2); - shadow_distance->set_double_minimum_value(0); - shadow_softness = add_row(tr("Shadow Softness"))->add_field(EFFECT_FIELD_DOUBLE, "shadowsoftness", 2); - shadow_softness->set_double_minimum_value(0); - shadow_opacity = add_row(tr("Shadow Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "shadowopacity", 2); - shadow_opacity->set_double_minimum_value(0); - shadow_opacity->set_double_maximum_value(100); + EffectRow* outline_color_row = add_row(tr("Outline Color")); + outline_color = new ColorField(outline_color_row, "outlinecolor"); + outline_color->SetColumnSpan(2); - size_val->set_double_default_value(48); - text_val->set_string_value(tr("Sample Text")); - halign_field->set_combo_index(1); - valign_field->set_combo_index(1); - word_wrap_field->set_bool_value(true); - outline_color->set_color_value(Qt::black); - shadow_color->set_color_value(Qt::black); - shadow_angle->set_double_default_value(45); - shadow_opacity->set_double_default_value(100); - shadow_softness->set_double_default_value(5); - shadow_distance->set_double_default_value(5); - shadow_opacity->set_double_default_value(80); - outline_width->set_double_default_value(20); + EffectRow* outline_width_row = add_row(tr("Outline Width")); + outline_width = new DoubleField(outline_width_row, "outlinewidth"); + outline_width->SetColumnSpan(2); + outline_width->SetMinimum(0); - outline_enable(false); - shadow_enable(false); + EffectRow* shadow_row = add_row(tr("Shadow")); + shadow_bool = new BoolField(shadow_row, "shadow"); + shadow_bool->SetColumnSpan(2); - connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool))); - connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool))); + EffectRow* shadow_color_row = add_row(tr("Shadow Color")); + shadow_color = new ColorField(shadow_color_row, "shadowcolor"); + shadow_color->SetColumnSpan(2); - vertPath = "common.vert"; - fragPath = "dropshadow.frag"; + EffectRow* shadow_angle_row = add_row(tr("Shadow Angle")); + shadow_angle = new DoubleField(shadow_angle_row, "shadowangle"); + shadow_angle->SetColumnSpan(2); + + EffectRow* shadow_distance_row = add_row(tr("Shadow Distance")); + shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance"); + shadow_distance->SetColumnSpan(2); + shadow_distance->SetMinimum(0); + + EffectRow* shadow_softness_row = add_row(tr("Shadow Softness")); + shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness"); + shadow_softness->SetColumnSpan(2); + shadow_softness->SetMinimum(0); + + EffectRow* shadow_opacity_row = add_row(tr("Shadow Opacity")); + shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity"); + shadow_opacity->SetColumnSpan(2); + shadow_opacity->SetMinimum(0); + shadow_opacity->SetMaximum(100); + + size_val->SetDefault(48); + text_val->SetValueAt(0, tr("Sample Text")); + halign_field->SetValueAt(0, Qt::AlignHCenter); + valign_field->SetValueAt(0, Qt::AlignVCenter); + word_wrap_field->SetValueAt(0, true); + outline_color->SetValueAt(0, QColor(Qt::black)); + shadow_color->SetValueAt(0, QColor(Qt::black)); + shadow_angle->SetDefault(45); + shadow_opacity->SetDefault(100); + shadow_softness->SetDefault(5); + shadow_distance->SetDefault(5); + shadow_opacity->SetDefault(80); + outline_width->SetDefault(20); + + outline_enable(false); + shadow_enable(false); + + connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool))); + connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool))); + + vertPath = "common.vert"; + fragPath = "dropshadow.frag"; } void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; + int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); + int r1 = rect.top(); + int r2 = rect.bottom(); + int c1 = rect.left(); + int c2 = rect.right(); - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; + int bpl = result.bytesPerLine(); + int rgba[4]; + unsigned char* p; - int i1 = 0; - int i2 = 3; + int i1 = 0; + int i2 = 3; - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); + if (alphaOnly) + i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r1) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p += bpl; + for (int j = r1; j < r2; j++, p += bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c1 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p += 4; + for (int j = c1; j < c2; j++, p += 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r2) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p -= bpl; + for (int j = r1; j < r2; j++, p -= bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c2 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } + p -= 4; + for (int j = c1; j < c2; j++, p -= 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } } void TextEffect::redraw(double timecode) { - QColor bkg = set_color_button->get_color_value(timecode); - bkg.setAlpha(0); - img.fill(bkg); + QColor bkg = set_color_button->GetColorAt(timecode); + bkg.setAlpha(0); + img.fill(bkg); - QPainter p(&img); - p.setRenderHint(QPainter::Antialiasing); - int width = img.width(); - int height = img.height(); + QPainter p(&img); + p.setRenderHint(QPainter::Antialiasing); + int width = img.width(); + int height = img.height(); - // set font - font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); - font.setFamily(set_font_combobox->get_font_name(timecode)); - font.setPointSize(size_val->get_double_value(timecode)); - p.setFont(font); - QFontMetrics fm(font); + // set font + font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); + font.setFamily(set_font_combobox->GetFontAt(timecode)); + font.setPointSize(qRound(size_val->GetDoubleAt(timecode))); + p.setFont(font); + QFontMetrics fm(font); - QStringList lines = text_val->get_string_value(timecode).split('\n'); + QStringList lines = text_val->GetStringAt(timecode).split('\n'); - // word wrap function - if (word_wrap_field->get_bool_value(timecode)) { - for (int i=0;i width) { - int last_space_index = 0; - for (int j=0;j width) { - break; - } else { - last_space_index = j; - } - } - } - if (last_space_index > 0) { - lines.insert(i+1, s.mid(last_space_index + 1)); - lines[i] = s.left(last_space_index); - } - } - } - } + // word wrap function + if (word_wrap_field->GetBoolAt(timecode)) { + for (int i=0;i width) { + int last_space_index = 0; + for (int j=0;j width) { + break; + } else { + last_space_index = j; + } + } + } + if (last_space_index > 0) { + lines.insert(i+1, s.mid(last_space_index + 1)); + lines[i] = s.left(last_space_index); + } + } + } + } - QPainterPath path; + QPainterPath path; - int text_height = fm.height()*lines.size(); + int text_height = fm.height()*lines.size(); - for (int i=0;iget_combo_data(timecode).toInt()) { - case Qt::AlignLeft: text_x = 0; break; - case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break; - case Qt::AlignJustify: - // add spaces until the string is too big - text_x = 0; - while (fm.width(lines.at(i)) < width) { - bool space = false; - QString spaced(lines.at(i)); - for (int i=0;iGetValueAt(timecode).toInt()) { + case Qt::AlignLeft: text_x = 0; break; + case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break; + case Qt::AlignJustify: + // add spaces until the string is too big + text_x = 0; + while (fm.width(lines.at(i)) < width) { + bool space = false; + QString spaced(lines.at(i)); + for (int i=0;i width || !space) { - break; - } else { - lines[i] = spaced; - } - } - break; - case Qt::AlignHCenter: - default: - text_x = (width/2) - (fm.width(lines.at(i))/2); - break; - } + // scan to next non-space + while (i < spaced.length() && spaced.at(i) == ' ') i++; + } + } + if (fm.width(spaced) > width || !space) { + break; + } else { + lines[i] = spaced; + } + } + break; + case Qt::AlignHCenter: + default: + text_x = (width/2) - (fm.width(lines.at(i))/2); + break; + } - switch (valign_field->get_combo_data(timecode).toInt()) { - case Qt::AlignTop: - text_y = (fm.height()*i)+fm.ascent(); - break; - case Qt::AlignBottom: - text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); - break; - case Qt::AlignVCenter: - default: - text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); - break; - } + switch (valign_field->GetValueAt(timecode).toInt()) { + case Qt::AlignTop: + text_y = (fm.height()*i)+fm.ascent(); + break; + case Qt::AlignBottom: + text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); + break; + case Qt::AlignVCenter: + default: + text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); + break; + } - path.addText(text_x, text_y, font, lines.at(i)); - } + path.addText(text_x, text_y, font, lines.at(i)); + } - // draw software shadow - if (shadow_bool->get_bool_value(timecode)) { - p.setPen(Qt::NoPen); + // draw software shadow + if (shadow_bool->GetBoolAt(timecode)) { + p.setPen(Qt::NoPen); // calculate offset using distance and angle - double angle = shadow_angle->get_double_value(timecode) * M_PI / 180.0; - double distance = qFloor(shadow_distance->get_double_value(timecode)); + double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0; + double distance = qFloor(shadow_distance->GetDoubleAt(timecode)); int shadow_x_offset = qRound(qCos(angle) * distance); int shadow_y_offset = qRound(qSin(angle) * distance); - QPainterPath shadow_path(path); + QPainterPath shadow_path(path); shadow_path.translate(shadow_x_offset, shadow_y_offset); - QColor col = shadow_color->get_color_value(timecode); - col.setAlpha(0); - img.fill(col); + QColor col = shadow_color->GetColorAt(timecode); + col.setAlpha(0); + img.fill(col); - col.setAlphaF(shadow_opacity->get_double_value(timecode)*0.01); - p.setBrush(col); - p.drawPath(shadow_path); + col.setAlphaF(shadow_opacity->GetDoubleAt(timecode)*0.01); + p.setBrush(col); + p.drawPath(shadow_path); - int blurSoftness = qFloor(shadow_softness->get_double_value(timecode)); + int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode)); if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, true); - } + } - // draw outline - int outline_width_val = outline_width->get_double_value(timecode); - if (outline_bool->get_bool_value(timecode) && outline_width_val > 0) { - QPen outline(outline_color->get_color_value(timecode)); - outline.setWidth(outline_width_val); - p.setPen(outline); - p.setBrush(Qt::NoBrush); - p.drawPath(path); - } + // draw outline + int outline_width_val = qCeil(outline_width->GetDoubleAt(timecode)); + if (outline_bool->GetBoolAt(timecode) && outline_width_val > 0) { + QPen outline(outline_color->GetColorAt(timecode)); + outline.setWidth(outline_width_val); + p.setPen(outline); + p.setBrush(Qt::NoBrush); + p.drawPath(path); + } - // draw "master" text - p.setPen(Qt::NoPen); - p.setBrush(set_color_button->get_color_value(timecode)); - p.drawPath(path); + // draw "master" text + p.setPen(Qt::NoPen); + p.setBrush(set_color_button->GetColorAt(timecode)); + p.drawPath(path); - p.end(); + p.end(); } void TextEffect::shadow_enable(bool e) { - close(); + close(); - shadow_color->set_enabled(e); - shadow_angle->set_enabled(e); - shadow_distance->set_enabled(e); - shadow_softness->set_enabled(e); - shadow_opacity->set_enabled(e); -} - -void TextEffect::text_edit_menu() { - QMenu menu; - - menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit())); - - menu.exec(QCursor::pos()); -} - -void TextEffect::open_text_edit() { - TextEditDialog ted(olive::MainWindow, text_val->get_current_data().toString()); - ted.exec(); - QString result = ted.get_string(); - if (!result.isEmpty()) { - text_val->set_current_data(result); - text_val->ui_element_change(); - } + shadow_color->SetEnabled(e); + shadow_angle->SetEnabled(e); + shadow_distance->SetEnabled(e); + shadow_softness->SetEnabled(e); + shadow_opacity->SetEnabled(e); } void TextEffect::outline_enable(bool e) { - outline_color->set_enabled(e); - outline_width->set_enabled(e); + outline_color->SetEnabled(e); + outline_width->SetEnabled(e); } diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h index d73b60de0..c3d7734a6 100644 --- a/effects/internal/texteffect.h +++ b/effects/internal/texteffect.h @@ -27,36 +27,34 @@ #include class TextEffect : public Effect { - Q_OBJECT + Q_OBJECT public: TextEffect(Clip* c, const EffectMeta *em); - void redraw(double timecode); + void redraw(double timecode); - EffectField* text_val; - EffectField* size_val; - EffectField* set_color_button; - EffectField* set_font_combobox; - EffectField* halign_field; - EffectField* valign_field; - EffectField* word_wrap_field; + StringField* text_val; + DoubleField* size_val; + ColorField* set_color_button; + FontField* set_font_combobox; + ComboField* halign_field; + ComboField* valign_field; + BoolField* word_wrap_field; - EffectField* outline_bool; - EffectField* outline_width; - EffectField* outline_color; + BoolField* outline_bool; + DoubleField* outline_width; + ColorField* outline_color; - EffectField* shadow_bool; - EffectField* shadow_angle; - EffectField* shadow_distance; - EffectField* shadow_color; - EffectField* shadow_softness; - EffectField* shadow_opacity; + BoolField* shadow_bool; + DoubleField* shadow_angle; + DoubleField* shadow_distance; + ColorField* shadow_color; + DoubleField* shadow_softness; + DoubleField* shadow_opacity; private slots: - void outline_enable(bool); - void shadow_enable(bool); - void text_edit_menu(); - void open_text_edit(); + void outline_enable(bool); + void shadow_enable(bool); private: - QFont font; + QFont font; }; #endif // TEXTEFFECT_H diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index b01e202d5..c69041954 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -46,45 +46,60 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { - enable_always_update = true; - enable_superimpose = true; + SetAlwaysUpdate(true); + SetFlags(Effect::SuperimposeFlag); EffectRow* tc_row = add_row(tr("Timecode")); - tc_select = tc_row->add_field(EFFECT_FIELD_COMBO, "tc_selector"); - tc_select->add_combo_item(tr("Sequence"), true); - tc_select->add_combo_item(tr("Media"), false); - tc_select->set_combo_index(0); + tc_select = new ComboField(tc_row, "tc_selector"); + tc_select->AddItem(tr("Sequence"), true); + tc_select->AddItem(tr("Media"), false); + tc_select->SetValueAt(0, true); - scale_val = add_row(tr("Scale"))->add_field(EFFECT_FIELD_DOUBLE, "scale", 2); - scale_val->set_double_minimum_value(1); - scale_val->set_double_default_value(100); - scale_val->set_double_maximum_value(1000); + EffectRow* scale_row = add_row(tr("Scale")); + scale_val = new DoubleField(scale_row, "scale"); + scale_val->SetColumnSpan(2); + scale_val->SetMinimum(1); + scale_val->SetDefault(100); + scale_val->SetMaximum(1000); - color_val = add_row(tr("Color"))->add_field(EFFECT_FIELD_COLOR, "color", 2); - color_val->set_color_value(Qt::white); + EffectRow* color_row = add_row(tr("Color")); + color_val = new ColorField(color_row, "color"); + color_val->SetColumnSpan(2); + color_val->SetValueAt(0, QColor(Qt::white)); - color_bg_val = add_row(tr("Background Color"))->add_field(EFFECT_FIELD_COLOR, "bgcolor", 2); - color_bg_val->set_color_value(Qt::black); + EffectRow* color_bg_row = add_row(tr("Background Color")); + color_bg_val = new ColorField(color_bg_row, "bgcolor"); + color_bg_val->SetColumnSpan(2); + color_bg_val->SetValueAt(0, QColor(Qt::black)); - bg_alpha = add_row(tr("Background Opacity"))->add_field(EFFECT_FIELD_DOUBLE, "bgalpha", 2); - bg_alpha->set_double_minimum_value(0); - bg_alpha->set_double_maximum_value(100); - bg_alpha->set_double_default_value(50); + EffectRow* bg_alpha_row = add_row(tr("Background Opacity")); + bg_alpha = new DoubleField(bg_alpha_row, "bgalpha"); + bg_alpha->SetColumnSpan(2); + bg_alpha->SetMinimum(0); + bg_alpha->SetDefault(50); + bg_alpha->SetMaximum(100); - EffectRow* offset = add_row(tr("Offset")); - offset_x_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsetx"); - offset_y_val = offset->add_field(EFFECT_FIELD_DOUBLE, "offsety"); + EffectRow* offset_row = add_row(tr("Offset")); + offset_x_val = new DoubleField(offset_row, "offsetx"); + offset_y_val = new DoubleField(offset_row, "offsety"); - prepend_text = add_row(tr("Prepend"))->add_field(EFFECT_FIELD_STRING, "prepend", 2); + EffectRow* prepent_text_row = add_row(tr("Prepend")); + prepend_text = new StringField(prepent_text_row, "prepend"); + prepend_text->SetColumnSpan(2); } void TimecodeEffect::redraw(double timecode) { - if (tc_select->get_combo_data(timecode).toBool()){ - display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate);} - else { + if (tc_select->GetValueAt(timecode).toBool()) { + display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(olive::ActiveSequence->playhead, + olive::CurrentConfig.timecode_view, + olive::ActiveSequence->frame_rate); + } else { double media_rate = parent_clip->media_frame_rate(); - display_timecode = prepend_text->get_string_value(timecode) + frame_to_timecode(timecode * media_rate, olive::CurrentConfig.timecode_view, media_rate);} + display_timecode = prepend_text->GetStringAt(timecode) + frame_to_timecode(qRound(timecode * media_rate), + olive::CurrentConfig.timecode_view, + media_rate); + } img.fill(Qt::transparent); QPainter p(&img); @@ -95,7 +110,7 @@ void TimecodeEffect::redraw(double timecode) { // set font font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); font.setFamily("Helvetica"); - font.setPixelSize(qCeil(scale_val->get_double_value(timecode)*.01*(height/10))); + font.setPixelSize(qCeil(scale_val->GetDoubleAt(timecode)*.01*(height/10))); p.setFont(font); QFontMetrics fm(font); @@ -104,12 +119,12 @@ void TimecodeEffect::redraw(double timecode) { int text_x, text_y, rect_y, offset_x, offset_y; int text_height = fm.height(); int text_width = fm.width(display_timecode); - QColor background_color = color_bg_val->get_color_value(timecode); - int alpha_val = bg_alpha->get_double_value(timecode)*2.55; + QColor background_color = color_bg_val->GetColorAt(timecode); + int alpha_val = qCeil(bg_alpha->GetDoubleAt(timecode)*2.55); background_color.setAlpha(alpha_val); - offset_x = int(offset_x_val->get_double_value(timecode)); - offset_y = int(offset_y_val->get_double_value(timecode)); + offset_x = int(offset_x_val->GetDoubleAt(timecode)); + offset_y = int(offset_y_val->GetDoubleAt(timecode)); text_x = offset_x + (width/2) - (text_width/2); text_y = offset_y + height - height/10; @@ -120,6 +135,6 @@ void TimecodeEffect::redraw(double timecode) { p.setPen(Qt::NoPen); p.setBrush(background_color); p.drawRect(QRect(text_x-fm.descent(), rect_y, text_width+fm.descent()*2, text_height)); - p.setBrush(color_val->get_color_value(timecode)); + p.setBrush(color_val->GetColorAt(timecode)); p.drawPath(path); } diff --git a/effects/internal/timecodeeffect.h b/effects/internal/timecodeeffect.h index 2caeb3276..1e8ba5ec8 100644 --- a/effects/internal/timecodeeffect.h +++ b/effects/internal/timecodeeffect.h @@ -27,18 +27,18 @@ #include class TimecodeEffect : public Effect { - Q_OBJECT + Q_OBJECT public: TimecodeEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); - EffectField * scale_val; - EffectField * color_val; - EffectField * color_bg_val; - EffectField * bg_alpha; - EffectField * offset_x_val; - EffectField * offset_y_val; - EffectField * prepend_text; - EffectField * tc_select; + DoubleField* scale_val; + ColorField* color_val; + ColorField* color_bg_val; + DoubleField* bg_alpha; + DoubleField* offset_x_val; + DoubleField* offset_y_val; + StringField* prepend_text; + ComboField* tc_select; private: QFont font; diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp index 777c3e878..132112a98 100644 --- a/effects/internal/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -29,44 +29,50 @@ #include "debug.h" ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) { - type_val = add_row(tr("Type"))->add_field(EFFECT_FIELD_COMBO, "type"); - type_val->add_combo_item("Sine", TONE_TYPE_SINE); + EffectRow* type_row = add_row(tr("Type")); + type_val = new ComboField(type_row, "type"); + type_val->AddItem(tr("Sine"), TONE_TYPE_SINE); - freq_val = add_row(tr("Frequency"))->add_field(EFFECT_FIELD_DOUBLE, "frequency"); - freq_val->set_double_minimum_value(20); - freq_val->set_double_maximum_value(20000); - freq_val->set_double_default_value(1000); + EffectRow* frequency_row = add_row(tr("Frequency")); + freq_val = new DoubleField(frequency_row, "frequency"); + freq_val->SetMinimum(20); + freq_val->SetMaximum(20000); + freq_val->SetDefault(1000); - amount_val = add_row(tr("Amount"))->add_field(EFFECT_FIELD_DOUBLE, "amount"); - amount_val->set_double_minimum_value(0); - amount_val->set_double_maximum_value(100); - amount_val->set_double_default_value(25); + EffectRow* amount_row = add_row(tr("Amount")); + amount_val = new DoubleField(amount_row, "amount"); + amount_val->SetMinimum(0); + amount_val->SetMaximum(100); + amount_val->SetDefault(25); - mix_val = add_row(tr("Mix"))->add_field(EFFECT_FIELD_BOOL, "mix"); - mix_val->set_bool_value(true); + EffectRow* mix_row = add_row(tr("Mix")); + mix_val = new BoolField(mix_row, "mix"); + mix_val->SetValueAt(0, true); } void ToneEffect::process_audio(double timecode_start, double timecode_end, quint8 *samples, int nb_bytes, int) { - double interval = (timecode_end - timecode_start)/nb_bytes; - for (int i=0;iget_double_value(timecode, true))/parent_clip->sequence->audio_frequency)*log_volume(amount_val->get_double_value(timecode, true)*0.01)*INT16_MAX)); - qint16 right_tone_sample = left_tone_sample; + qint16 left_tone_sample = qint16(qRound(qSin((2*M_PI*sinX*freq_val->GetDoubleAt(timecode)) + /parent_clip->sequence->audio_frequency) + *log_volume(amount_val->GetDoubleAt(timecode)*0.01)*INT16_MAX)); + qint16 right_tone_sample = left_tone_sample; - // mix with source audio - if (mix_val->get_bool_value(timecode, true)) { - qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); - qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - left_tone_sample = mix_audio_sample(left_tone_sample, left_sample); - right_tone_sample = mix_audio_sample(right_tone_sample, right_sample); - } + // mix with source audio + if (mix_val->GetBoolAt(timecode)) { + qint16 left_sample = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint16 right_sample = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + left_tone_sample = mix_audio_sample(left_tone_sample, left_sample); + right_tone_sample = mix_audio_sample(right_tone_sample, right_sample); + } - samples[i+3] = quint8(right_tone_sample >> 8); - samples[i+2] = quint8(right_tone_sample); - samples[i+1] = quint8(left_tone_sample >> 8); - samples[i] = quint8(left_tone_sample); + samples[i+3] = quint8(right_tone_sample >> 8); + samples[i+2] = quint8(right_tone_sample); + samples[i+1] = quint8(left_tone_sample >> 8); + samples[i] = quint8(left_tone_sample); - sinX++; - } + sinX++; + } } diff --git a/effects/internal/toneeffect.h b/effects/internal/toneeffect.h index 2007ac70e..2b0223e47 100644 --- a/effects/internal/toneeffect.h +++ b/effects/internal/toneeffect.h @@ -24,17 +24,17 @@ #include "project/effect.h" class ToneEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - ToneEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + ToneEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* type_val; - EffectField* freq_val; - EffectField* amount_val; - EffectField* mix_val; + ComboField* type_val; + DoubleField* freq_val; + DoubleField* amount_val; + BoolField* mix_val; private: - int sinX; + int sinX; }; #endif // TONEEFFECT_H diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 07dd08d3f..0662bc0d1 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -44,230 +44,197 @@ #include "ui/viewerwidget.h" TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { - enable_coords = true; + SetFlags(Effect::CoordsFlag); - EffectRow* position_row = add_row(tr("Position")); - position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X - position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y + EffectRow* position_row = add_row(tr("Position")); - EffectRow* scale_row = add_row(tr("Scale")); - scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected) - scale_x->set_double_minimum_value(0); - scale_x->set_double_maximum_value(3000); - scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected) - scale_y->set_double_minimum_value(0); - scale_y->set_double_maximum_value(3000); + position_x = new DoubleField(position_row, "posx"); // position X + position_y = new DoubleField(position_row, "posy"); // position Y - EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); - uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option + EffectRow* scale_row = add_row(tr("Scale")); - EffectRow* rotation_row = add_row(tr("Rotation")); - rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation"); + // scale X (and Y is uniform scale is selected) + scale_x = new DoubleField(scale_row, "scalex"); + scale_x->SetMinimum(0); - EffectRow* anchor_point_row = add_row(tr("Anchor Point")); - 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 + // scale Y (disabled if uniform scale is selected) + scale_y = new DoubleField(scale_row, "scaley"); + scale_y->SetMinimum(0); - EffectRow* opacity_row = add_row(tr("Opacity")); - opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity - opacity->set_double_minimum_value(0); - opacity->set_double_maximum_value(100); + EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); - EffectRow* blend_mode_row = add_row(tr("Blend Mode")); - blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode", 2); // blend mode - blend_mode_box->add_combo_item(tr("Normal"), BLEND_MODE_NORMAL); - blend_mode_box->add_combo_item(tr("Darken"), BLEND_MODE_DARKEN); - blend_mode_box->add_combo_item(tr("Multiply"), BLEND_MODE_MULTIPLY); - blend_mode_box->add_combo_item(tr("Color Burn"), BLEND_MODE_COLORBURN); - blend_mode_box->add_combo_item(tr("Linear Burn"), BLEND_MODE_LINEARBURN); - blend_mode_box->add_combo_item(tr("Lighten"), BLEND_MODE_LIGHTEN); - blend_mode_box->add_combo_item(tr("Screen"), BLEND_MODE_SCREEN); - blend_mode_box->add_combo_item(tr("Color Dodge"), BLEND_MODE_COLORDODGE); - blend_mode_box->add_combo_item(tr("Linear Dodge (Add)"), BLEND_MODE_LINEARDODGE); - blend_mode_box->add_combo_item(tr("Overlay"), BLEND_MODE_OVERLAY); - blend_mode_box->add_combo_item(tr("Soft Light"), BLEND_MODE_SOFTLIGHT); - blend_mode_box->add_combo_item(tr("Hard Light"), BLEND_MODE_HARDLIGHT); - blend_mode_box->add_combo_item(tr("Vivid Light"), BLEND_MODE_VIVIDLIGHT); - blend_mode_box->add_combo_item(tr("Linear Light"), BLEND_MODE_LINEARLIGHT); - blend_mode_box->add_combo_item(tr("Pin Light"), BLEND_MODE_PINLIGHT); - blend_mode_box->add_combo_item(tr("Hard Mix"), BLEND_MODE_HARDMIX); - blend_mode_box->add_combo_item(tr("Difference"), BLEND_MODE_DIFFERENCE); - blend_mode_box->add_combo_item(tr("Exclusion"), BLEND_MODE_EXCLUSION); - blend_mode_box->add_combo_item(tr("Reflect"), BLEND_MODE_REFLECT); -// blend_mode_box->add_combo_item(tr("Subtract"), BLEND_MODE_SUBTRACT); - blend_mode_box->add_combo_item(tr("Substract"), BLEND_MODE_SUBSTRACT); -// blend_mode_box->add_combo_item(tr("Add"), BLEND_MODE_ADD); - blend_mode_box->add_combo_item(tr("Average"), BLEND_MODE_AVERAGE); - blend_mode_box->add_combo_item(tr("Glow"), BLEND_MODE_GLOW); - blend_mode_box->add_combo_item(tr("Negation"), BLEND_MODE_NEGATION); - blend_mode_box->add_combo_item(tr("Phoenix"), BLEND_MODE_PHOENIX); + uniform_scale_field = new BoolField(uniform_scale_row, "uniformscale"); // uniform scale option - // set up gizmos - top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_left_gizmo->set_cursor(Qt::SizeFDiagCursor); - top_left_gizmo->x_field1 = scale_x; + EffectRow* rotation_row = add_row(tr("Rotation")); - top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_center_gizmo->set_cursor(Qt::SizeVerCursor); - top_center_gizmo->y_field1 = scale_x; + rotation = new DoubleField(rotation_row, "rotation"); - top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); - top_right_gizmo->x_field1 = scale_x; + EffectRow* anchor_point_row = add_row(tr("Anchor Point")); - bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); - bottom_left_gizmo->x_field1 = scale_x; + anchor_x_box = new DoubleField(anchor_point_row, "anchorx"); // anchor point X + anchor_y_box = new DoubleField(anchor_point_row, "anchory"); // anchor point Y - bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); - bottom_center_gizmo->y_field1 = scale_x; + EffectRow* opacity_row = add_row(tr("Opacity")); - bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); - bottom_right_gizmo->x_field1 = scale_x; + // opacity + opacity = new DoubleField(opacity_row, "opacity"); + opacity->SetMinimum(0); + opacity->SetMaximum(100); - left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - left_center_gizmo->set_cursor(Qt::SizeHorCursor); - left_center_gizmo->x_field1 = scale_x; + EffectRow* blend_mode_row = add_row(tr("Blend Mode")); - right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - right_center_gizmo->set_cursor(Qt::SizeHorCursor); - right_center_gizmo->x_field1 = scale_x; + // blend mode + blend_mode_box = new ComboField(blend_mode_row, "blendmode"); + blend_mode_box->SetColumnSpan(2); + blend_mode_box->AddItem(tr("Normal"), ""); - anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET); - anchor_gizmo->set_cursor(Qt::SizeAllCursor); - anchor_gizmo->x_field1 = anchor_x_box; - anchor_gizmo->y_field1 = anchor_y_box; - anchor_gizmo->x_field2 = position_x; - anchor_gizmo->y_field2 = position_y; + // set up gizmos + top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_left_gizmo->set_cursor(Qt::SizeFDiagCursor); + top_left_gizmo->x_field1 = scale_x; - rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); - rotate_gizmo->color = Qt::green; - rotate_gizmo->set_cursor(Qt::SizeAllCursor); - rotate_gizmo->x_field1 = rotation; + top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_center_gizmo->set_cursor(Qt::SizeVerCursor); + top_center_gizmo->y_field1 = scale_x; - rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); - rect_gizmo->x_field1 = position_x; - rect_gizmo->y_field1 = position_y; + top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); + top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); + top_right_gizmo->x_field1 = scale_x; - connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); + bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); + bottom_left_gizmo->x_field1 = scale_x; - // set defaults - uniform_scale_field->set_bool_value(true); - blend_mode_box->set_combo_index(0); - set = false; - refresh(); -} + bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); + bottom_center_gizmo->y_field1 = scale_x; -void adjust_field(EffectField* field, double old_offset, double new_offset) { - if (field->keyframes.size() > 0) { - for (int i=0;ikeyframes.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); - } + bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); + bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); + bottom_right_gizmo->x_field1 = scale_x; + + left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + left_center_gizmo->set_cursor(Qt::SizeHorCursor); + left_center_gizmo->x_field1 = scale_x; + + right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + right_center_gizmo->set_cursor(Qt::SizeHorCursor); + right_center_gizmo->x_field1 = scale_x; + + anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET); + anchor_gizmo->set_cursor(Qt::SizeAllCursor); + anchor_gizmo->x_field1 = anchor_x_box; + anchor_gizmo->y_field1 = anchor_y_box; + anchor_gizmo->x_field2 = position_x; + anchor_gizmo->y_field2 = position_y; + + rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); + rotate_gizmo->color = Qt::green; + rotate_gizmo->set_cursor(Qt::SizeAllCursor); + rotate_gizmo->x_field1 = rotation; + + rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); + rect_gizmo->x_field1 = position_x; + rect_gizmo->y_field1 = position_y; + + connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); + + // set defaults + uniform_scale_field->SetValueAt(0, true); + blend_mode_box->SetValueAt(0, ""); + anchor_x_box->SetDefault(0); + anchor_y_box->SetDefault(0); + opacity->SetDefault(100); + scale_x->SetDefault(100); + scale_y->SetDefault(100); + + refresh(); } void TransformEffect::refresh() { - if (parent_clip != nullptr && parent_clip->sequence != nullptr) { - double new_default_pos_x = parent_clip->sequence->width/2; - double new_default_pos_y = parent_clip->sequence->height/2; + if (parent_clip != nullptr && parent_clip->sequence != nullptr) { - /*if (set) { - adjust_field(position_x, default_pos_x, new_default_pos_x); - adjust_field(position_y, default_pos_y, new_default_pos_y); - }*/ + position_x->SetDefault(parent_clip->sequence->width/2); + position_y->SetDefault(parent_clip->sequence->height/2); - double default_pos_x = new_default_pos_x; - double default_pos_y = new_default_pos_y; + double x_percent_multipler = 200.0 / parent_clip->sequence->width; + double y_percent_multipler = 200.0 / parent_clip->sequence->height; - position_x->set_double_default_value(default_pos_x); - position_y->set_double_default_value(default_pos_y); - scale_x->set_double_default_value(100); - scale_y->set_double_default_value(100); + top_left_gizmo->x_field_multi1 = -x_percent_multipler; + top_left_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->y_field_multi1 = -y_percent_multipler; + bottom_left_gizmo->x_field_multi1 = -x_percent_multipler; + bottom_left_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->y_field_multi1 = y_percent_multipler; + left_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; - anchor_x_box->set_double_default_value(0); - anchor_y_box->set_double_default_value(0); - opacity->set_double_default_value(100); - - double x_percent_multipler = 200.0 / parent_clip->sequence->width; - double y_percent_multipler = 200.0 / parent_clip->sequence->height; - top_left_gizmo->x_field_multi1 = -x_percent_multipler; - top_left_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->y_field_multi1 = -y_percent_multipler; - bottom_left_gizmo->x_field_multi1 = -x_percent_multipler; - bottom_left_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->y_field_multi1 = y_percent_multipler; - left_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; - - set = true; - } + } } void TransformEffect::toggle_uniform_scale(bool enabled) { - scale_y->set_enabled(!enabled); + scale_y->SetEnabled(!enabled); - top_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 ? nullptr : scale_y; - top_right_gizmo->y_field1 = enabled ? nullptr : scale_y; - bottom_left_gizmo->y_field1 = enabled ? nullptr : scale_y; - bottom_right_gizmo->y_field1 = enabled ? nullptr : scale_y; + top_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 ? nullptr : scale_y; + top_right_gizmo->y_field1 = enabled ? nullptr : scale_y; + bottom_left_gizmo->y_field1 = enabled ? nullptr : scale_y; + bottom_right_gizmo->y_field1 = enabled ? nullptr : scale_y; } void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { - // position - glTranslated(position_x->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0); + // position + glTranslated(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2), + position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2), + 0); - // anchor point - int anchor_x_offset = qRound(anchor_x_box->get_double_value(timecode)); - int anchor_y_offset = qRound(anchor_y_box->get_double_value(timecode)); - coords.vertexTopLeftX -= anchor_x_offset; - coords.vertexTopRightX -= anchor_x_offset; - coords.vertexBottomLeftX -= anchor_x_offset; - coords.vertexBottomRightX -= anchor_x_offset; - coords.vertexTopLeftY -= anchor_y_offset; - coords.vertexTopRightY -= anchor_y_offset; - coords.vertexBottomLeftY -= anchor_y_offset; - coords.vertexBottomRightY -= anchor_y_offset; + // anchor point + int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode)); + int anchor_y_offset = qRound(anchor_y_box->GetDoubleAt(timecode)); + coords.vertexTopLeftX -= anchor_x_offset; + coords.vertexTopRightX -= anchor_x_offset; + coords.vertexBottomLeftX -= anchor_x_offset; + coords.vertexBottomRightX -= anchor_x_offset; + coords.vertexTopLeftY -= anchor_y_offset; + coords.vertexTopRightY -= anchor_y_offset; + coords.vertexBottomLeftY -= anchor_y_offset; + coords.vertexBottomRightY -= anchor_y_offset; - // rotation - glRotated(rotation->get_double_value(timecode), 0, 0, 1); + // rotation + glRotated(rotation->GetDoubleAt(timecode), 0, 0, 1); - // scale - double sx = scale_x->get_double_value(timecode)*0.01; - double sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01; - glScaled(sx, sy, 1); + // scale + double sx = scale_x->GetDoubleAt(timecode)*0.01; + double sy = (uniform_scale_field->GetBoolAt(timecode)) ? sx : scale_y->GetDoubleAt(timecode)*0.01; + glScaled(sx, sy, 1); - // blend mode - coords.blendmode = blend_mode_box->get_combo_data(timecode).toInt(); + // blend mode + coords.blendmode = blend_mode_box->GetValueAt(timecode).toInt(); - // opacity - coords.opacity *= float(opacity->get_double_value(timecode)*0.01); + // opacity + coords.opacity *= float(opacity->GetDoubleAt(timecode)*0.01); } void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) { - top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5)); - top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5)); - bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5)); - bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); - left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5)); + top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); + top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5)); + top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); + right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5)); + bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); + bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5)); + bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5)); - rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1)); + rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1)); - rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); - rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); - rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); - rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); + rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); + rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); + rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); + rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); } diff --git a/effects/internal/transformeffect.h b/effects/internal/transformeffect.h index f815659ed..13b007bc0 100644 --- a/effects/internal/transformeffect.h +++ b/effects/internal/transformeffect.h @@ -24,40 +24,38 @@ #include "project/effect.h" class TransformEffect : public Effect { - Q_OBJECT + Q_OBJECT public: TransformEffect(Clip* c, const EffectMeta* em); - void refresh(); - void process_coords(double timecode, GLTextureCoords& coords, int data); + void refresh(); + void process_coords(double timecode, GLTextureCoords& coords, int data); - void gizmo_draw(double timecode, GLTextureCoords& coords); + void gizmo_draw(double timecode, GLTextureCoords& coords); public slots: - void toggle_uniform_scale(bool enabled); + void toggle_uniform_scale(bool enabled); private: - EffectField* position_x; - EffectField* position_y; - EffectField* scale_x; - EffectField* scale_y; - EffectField* uniform_scale_field; - EffectField* rotation; - EffectField* anchor_x_box; - EffectField* anchor_y_box; - EffectField* opacity; - EffectField* blend_mode_box; + DoubleField* position_x; + DoubleField* position_y; + DoubleField* scale_x; + DoubleField* scale_y; + BoolField* uniform_scale_field; + DoubleField* rotation; + DoubleField* anchor_x_box; + DoubleField* anchor_y_box; + DoubleField* opacity; + ComboField* blend_mode_box; - EffectGizmo* top_left_gizmo; - EffectGizmo* top_center_gizmo; - EffectGizmo* top_right_gizmo; - EffectGizmo* bottom_left_gizmo; - EffectGizmo* bottom_center_gizmo; - EffectGizmo* bottom_right_gizmo; - EffectGizmo* left_center_gizmo; - EffectGizmo* right_center_gizmo; - EffectGizmo* anchor_gizmo; - EffectGizmo* rotate_gizmo; - EffectGizmo* rect_gizmo; - - bool set; + EffectGizmo* top_left_gizmo; + EffectGizmo* top_center_gizmo; + EffectGizmo* top_right_gizmo; + EffectGizmo* bottom_left_gizmo; + EffectGizmo* bottom_center_gizmo; + EffectGizmo* bottom_right_gizmo; + EffectGizmo* left_center_gizmo; + EffectGizmo* right_center_gizmo; + EffectGizmo* anchor_gizmo; + EffectGizmo* rotate_gizmo; + EffectGizmo* rect_gizmo; }; #endif // TRANSFORMEFFECT_H diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp index 23cf1a45f..a08427a41 100644 --- a/effects/internal/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -29,41 +29,40 @@ #include "ui/collapsiblewidget.h" VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* volume_row = add_row(tr("Volume")); - volume_val = volume_row->add_field(EFFECT_FIELD_DOUBLE, "volume"); + EffectRow* volume_row = add_row(tr("Volume")); + volume_val = new DoubleField(volume_row, "volume"); - // set defaults - volume_val->set_double_default_value(1); - static_cast(volume_val->get_ui_element())->set_display_type(LABELSLIDER_DECIBEL); + // set defaults + volume_val->SetDefault(1); + volume_val->SetDisplayType(LabelSlider::LABELSLIDER_DECIBEL); } void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { - double interval = (timecode_end-timecode_start)/nb_bytes; - for (int i=0;iget_double_value(timecode_start+(interval*i), true)); - double vol_val = volume_val->get_double_value(timecode_start+(interval*i), true); + double interval = (timecode_end-timecode_start)/nb_bytes; + for (int i=0;iGetDoubleAt(timecode_start+(interval*i)); - qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); - qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); + qint32 right_samp = qint16(((samples[i+3] & 0xFF) << 8) | (samples[i+2] & 0xFF)); + qint32 left_samp = qint16(((samples[i+1] & 0xFF) << 8) | (samples[i] & 0xFF)); - left_samp *= vol_val; - right_samp *= vol_val; + left_samp *= vol_val; + right_samp *= vol_val; - if (left_samp > INT16_MAX) { - left_samp = INT16_MAX; - } else if (left_samp < INT16_MIN) { - left_samp = INT16_MIN; - } + if (left_samp > INT16_MAX) { + left_samp = INT16_MAX; + } else if (left_samp < INT16_MIN) { + left_samp = INT16_MIN; + } - if (right_samp > INT16_MAX) { - right_samp = INT16_MAX; - } else if (right_samp < INT16_MIN) { - right_samp = INT16_MIN; - } + if (right_samp > INT16_MAX) { + right_samp = INT16_MAX; + } else if (right_samp < INT16_MIN) { + right_samp = INT16_MIN; + } - samples[i+3] = (quint8) (right_samp >> 8); - samples[i+2] = (quint8) right_samp; - samples[i+1] = (quint8) (left_samp >> 8); - samples[i] = (quint8) left_samp; - } + samples[i+3] = (quint8) (right_samp >> 8); + samples[i+2] = (quint8) right_samp; + samples[i+1] = (quint8) (left_samp >> 8); + samples[i] = (quint8) left_samp; + } } diff --git a/effects/internal/volumeeffect.h b/effects/internal/volumeeffect.h index 6d143f5af..584c6c00c 100644 --- a/effects/internal/volumeeffect.h +++ b/effects/internal/volumeeffect.h @@ -24,12 +24,12 @@ #include "project/effect.h" class VolumeEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - VolumeEffect(Clip* c, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + VolumeEffect(Clip* c, const EffectMeta* em); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - EffectField* volume_val; + DoubleField* volume_val; }; #endif // VOLUMEEFFECT_H diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index 89fa02cdc..aa38f2470 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -106,7 +106,7 @@ typedef int32_t (*processEventsFuncPtr)(VstEvents *events); typedef void (*processFuncPtr)(AEffect *effect, float **inputs, float **outputs, int32_t sampleFrames); void VSTHost::loadPlugin() { - QString dll_fn = file_field->get_filename(0, true); + QString dll_fn = file_field->GetFileAt(0); if (dll_fn.isEmpty()) { return; @@ -266,7 +266,8 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) { outputs[channel] = new float[BLOCK_SIZE]; } - file_field = add_row(tr("Plugin"), true, false)->add_field(EFFECT_FIELD_FILE, "filename"); + EffectRow* file_row = add_row(tr("Plugin"), true, false); + file_field = new FileField(file_row, "filename"); connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin())); EffectRow* interface_row = add_row(tr("Interface"), false, false); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index cd2d2ae48..cebd2e11d 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -35,42 +35,42 @@ typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t i #include class VSTHost : public Effect { - Q_OBJECT + Q_OBJECT public: VSTHost(Clip* c, const EffectMeta* em); - ~VSTHost(); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + ~VSTHost(); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); - void custom_load(QXmlStreamReader& stream); - void save(QXmlStreamWriter& stream); + void custom_load(QXmlStreamReader& stream); + void save(QXmlStreamWriter& stream); private slots: - void show_interface(bool show); - void uncheck_show_button(); - void change_plugin(); + void show_interface(bool show); + void uncheck_show_button(); + void change_plugin(); private: - EffectField* file_field; + FileField* file_field; - void loadPlugin(); - void freePlugin(); - dispatcherFuncPtr dispatcher; - AEffect* plugin; - bool configurePluginCallbacks(); - void startPlugin(); - void stopPlugin(); - void resumePlugin(); - void suspendPlugin(); - bool canPluginDo(char *canDoString); - void processAudio(long numFrames); - float** inputs; - float** outputs; - QDialog* dialog; - QPushButton* show_interface_btn; - QByteArray data_cache; + void loadPlugin(); + void freePlugin(); + dispatcherFuncPtr dispatcher; + AEffect* plugin; + bool configurePluginCallbacks(); + void startPlugin(); + void stopPlugin(); + void resumePlugin(); + void suspendPlugin(); + bool canPluginDo(char *canDoString); + void processAudio(long numFrames); + float** inputs; + float** outputs; + QDialog* dialog; + QPushButton* show_interface_btn; + QByteArray data_cache; #if defined(__APPLE__) - CFBundleRef bundle; + CFBundleRef bundle; #else - ModulePtr modulePtr; + ModulePtr modulePtr; #endif }; diff --git a/olive.pro b/olive.pro index 5f844a844..a826f8380 100644 --- a/olive.pro +++ b/olive.pro @@ -116,8 +116,6 @@ SOURCES += \ project/effect.cpp \ project/transition.cpp \ project/effectrow.cpp \ - project/effectfield.cpp \ - effects/internal/cubetransition.cpp \ project/effectgizmo.cpp \ io/clipboard.cpp \ ui/resizablescrollbar.cpp \ @@ -162,7 +160,15 @@ SOURCES += \ dialogs/clippropertiesdialog.cpp \ rendering/framebufferobject.cpp \ ui/updatenotification.cpp \ - ui/icons.cpp + ui/icons.cpp \ + project/effectfields/doublefield.cpp \ + project/effectfields/fontfield.cpp \ + project/effectfields/effectfield.cpp \ + project/effectfields/colorfield.cpp \ + project/effectfields/stringfield.cpp \ + project/effectfields/boolfield.cpp \ + project/effectfields/combofield.cpp \ + project/effectfields/filefield.cpp HEADERS += \ mainwindow.h \ @@ -229,7 +235,6 @@ HEADERS += \ project/effect.h \ project/transition.h \ project/effectrow.h \ - project/effectfield.h \ effects/internal/cubetransition.h \ project/effectgizmo.h \ io/clipboard.h \ @@ -276,7 +281,16 @@ HEADERS += \ dialogs/clippropertiesdialog.h \ rendering/framebufferobject.h \ ui/updatenotification.h \ - ui/icons.h + ui/icons.h \ + project/effectfields/doublefield.h \ + project/effectfields/fontfield.h \ + project/effectfields/effectfield.h \ + project/effectfields.h \ + project/effectfields/colorfield.h \ + project/effectfields/stringfield.h \ + project/effectfields/boolfield.h \ + project/effectfields/combofield.h \ + project/effectfields/filefield.h FORMS += diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index bd0494389..4f5806aaf 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -31,9 +31,10 @@ #include "ui/labelslider.h" #include "ui/graphview.h" #include "project/effect.h" -#include "project/effectfield.h" +#include "project/effectfields.h" #include "project/effectrow.h" #include "project/clip.h" +#include "rendering/renderfunctions.h" #include "panels.h" #include "debug.h" @@ -142,8 +143,12 @@ void GraphEditor::update_panel() { int slider_index = 0; for (int i=0;ifieldCount();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); + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { + slider_proxies.at(slider_index)->set_value( + row->field(i)->GetValueAt(playhead_to_clip_seconds(field->GetParentRow()->parent_effect->parent_clip, + olive::ActiveSequence->playhead)).toDouble(), + false + ); slider_index++; } } @@ -175,10 +180,10 @@ void GraphEditor::set_row(EffectRow *r) { if (r != nullptr && r->isKeyframing()) { for (int i=0;ifieldCount();i++) { EffectField* field = r->field(i); - if (field->type == EFFECT_FIELD_DOUBLE) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { QPushButton* slider_button = new QPushButton(); slider_button->setCheckable(true); - slider_button->setChecked(field->is_enabled()); + slider_button->setChecked(field->IsEnabled()); slider_button->setIcon(QIcon(":/icons/record.svg")); slider_button->setProperty("field", i); slider_button->setIconSize(slider_button->iconSize()*0.5); @@ -192,7 +197,7 @@ void GraphEditor::set_row(EffectRow *r) { slider_proxies.append(slider); value_layout->addWidget(slider); - slider_proxy_sources.append(static_cast(field->ui_element)); + //slider_proxy_sources.append(static_cast(field->ui_element)); found_vals = true; } @@ -203,7 +208,7 @@ void GraphEditor::set_row(EffectRow *r) { row = r; current_row_desc->setText(row->parent_effect->parent_clip->name() + " :: " + row->parent_effect->meta->name - + " :: " + row->get_name()); + + " :: " + row->name()); header->set_visible_in(r->parent_effect->parent_clip->timeline_in()); connect(keyframe_nav, SIGNAL(goto_previous_key()), row, SLOT(goto_previous_key())); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index e857185d3..c6455b347 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -82,7 +82,7 @@ Viewer::Viewer(QWidget *parent) : current_timecode_slider->set_minimum_value(0); current_timecode_slider->set_default_value(qSNaN()); current_timecode_slider->set_value(0, false); - current_timecode_slider->set_display_type(LABELSLIDER_FRAMENUMBER); + current_timecode_slider->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); connect(current_timecode_slider, SIGNAL(valueChanged()), this, SLOT(update_playhead())); recording_flasher.setInterval(500); diff --git a/project/clip.cpp b/project/clip.cpp index f40508b4b..aaf532da3 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -574,8 +574,8 @@ bool Clip::Retrieve() int frame_size = frame->linesize[0]*frame->height; for (int i=0;ienable_image && e->is_enabled()) { + Effect* e = effects.at(i).get(); + if ((e->Flags() & Effect::ImageFlag) && e->is_enabled()) { if (data_buffer_1 == frame->data[0]) { data_buffer_1 = new uint8_t[frame_size]; data_buffer_2 = new uint8_t[frame_size]; diff --git a/project/effect.cpp b/project/effect.cpp index a49ae6977..a437bf125 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -70,871 +70,897 @@ QVector effects; EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { - if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { - // must be an internal effect - switch (em->internal) { - case EFFECT_INTERNAL_TRANSFORM: return EffectPtr(new TransformEffect(c, em)); - case EFFECT_INTERNAL_TEXT: return EffectPtr(new TextEffect(c, em)); - case EFFECT_INTERNAL_TIMECODE: return EffectPtr(new TimecodeEffect(c, em)); - case EFFECT_INTERNAL_SOLID: return EffectPtr(new SolidEffect(c, em)); - case EFFECT_INTERNAL_NOISE: return EffectPtr(new AudioNoiseEffect(c, em)); - case EFFECT_INTERNAL_VOLUME: return EffectPtr(new VolumeEffect(c, em)); - case EFFECT_INTERNAL_PAN: return EffectPtr(new PanEffect(c, em)); - case EFFECT_INTERNAL_TONE: return EffectPtr(new ToneEffect(c, em)); - case EFFECT_INTERNAL_SHAKE: return EffectPtr(new ShakeEffect(c, em)); - case EFFECT_INTERNAL_CORNERPIN: return EffectPtr(new CornerPinEffect(c, em)); - case EFFECT_INTERNAL_FILLLEFTRIGHT: return EffectPtr(new FillLeftRightEffect(c, em)); + if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { + // must be an internal effect + switch (em->internal) { + case EFFECT_INTERNAL_TRANSFORM: return std::make_shared(c, em); + case EFFECT_INTERNAL_TEXT: return std::make_shared(c, em); + case EFFECT_INTERNAL_TIMECODE: return std::make_shared(c, em); + case EFFECT_INTERNAL_SOLID: return std::make_shared(c, em); + case EFFECT_INTERNAL_NOISE: return std::make_shared(c, em); + case EFFECT_INTERNAL_VOLUME: return std::make_shared(c, em); + case EFFECT_INTERNAL_PAN: return std::make_shared(c, em); + case EFFECT_INTERNAL_TONE: return std::make_shared(c, em); + case EFFECT_INTERNAL_SHAKE: return std::make_shared(c, em); + case EFFECT_INTERNAL_CORNERPIN: return std::make_shared(c, em); + case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared(c, em); #ifndef NOVST - case EFFECT_INTERNAL_VST: return EffectPtr(new VSTHost(c, em)); + case EFFECT_INTERNAL_VST: return std::make_shared(c, em); #endif #ifndef NOFREI0R - case EFFECT_INTERNAL_FREI0R: return EffectPtr(new Frei0rEffect(c, em)); + case EFFECT_INTERNAL_FREI0R: return std::make_shared(c, em); #endif - } - } else if (!em->filename.isEmpty()) { - // load effect from file - return EffectPtr(new Effect(c, em)); - } else { - qCritical() << "Invalid effect data"; + } + } else if (!em->filename.isEmpty()) { + // load effect from file + return std::make_shared(c, em); + } else { + qCritical() << "Invalid effect data"; QMessageBox::critical(olive::MainWindow, - QCoreApplication::translate("Effect", "Invalid effect"), - QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); - } - return nullptr; + QCoreApplication::translate("Effect", "Invalid effect"), + QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); + } + return nullptr; } const EffectMeta* Effect::GetInternalMeta(int internal_id, int type) { - for (int i=0;ienabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); - ui = new QWidget(container); - ui_layout = new QGridLayout(ui); - ui_layout->setSpacing(4); - container->setContents(ui); + // set up base UI + container = new CollapsibleWidget(); + connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); + ui = new QWidget(container); + ui_layout = new QGridLayout(ui); + ui_layout->setSpacing(4); + 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&))); - if (em != nullptr) { - // set up UI from effect file - container->setText(em->name); + if (em != nullptr) { + // set up UI from effect file + container->setText(em->name); - if (!em->filename.isEmpty() && em->internal == -1) { - QFile effect_file(em->filename); - if (effect_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&effect_file); + if (!em->filename.isEmpty() && em->internal == -1) { + QFile effect_file(em->filename); + if (effect_file.open(QFile::ReadOnly)) { + QXmlStreamReader reader(&effect_file); - while (!reader.atEnd()) { - if (reader.name() == "row" && reader.isStartElement()) { - QString row_name; - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename << "- ID cannot be empty."; - } else if (type > -1) { - EffectField* field = row->add_field(type, id); - connect(field, SIGNAL(changed()), this, SLOT(field_changed())); - switch (type) { - case EFFECT_FIELD_DOUBLE: - for (int i=0;iset_double_default_value(attr.value().toDouble()); - } else if (attr.name() == "min") { - field->set_double_minimum_value(attr.value().toDouble()); - } else if (attr.name() == "max") { - field->set_double_maximum_value(attr.value().toDouble()); - } - } - break; - case EFFECT_FIELD_COLOR: - { - QColor color; - for (int i=0;iset_color_value(color); - } - break; - case EFFECT_FIELD_STRING: - for (int i=0;iset_string_value(attr.value().toString()); - } - } - break; - case EFFECT_FIELD_BOOL: - for (int i=0;iset_bool_value(attr.value() == "1"); - } - } - break; - case EFFECT_FIELD_COMBO: - { - int combo_index = 0; - for (int i=0;iadd_combo_item(reader.text().toString(), 0); - } - } - field->set_combo_index(combo_index); - } - break; - case EFFECT_FIELD_FONT: - for (int i=0;iset_font_name(attr.value().toString()); - } - } - break; - case EFFECT_FIELD_FILE: - for (int i=0;iset_filename(attr.value().toString()); - } - } - break; - } - } - } - } - } - } else if (reader.name() == "shader" && reader.isStartElement()) { - enable_shader = true; - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename; - enable_superimpose = false; - } - break; - } - } - }*/ - reader.readNext(); - } + if (id.isEmpty()) { + qCritical() << "Couldn't load field from" << em->filename << "- ID cannot be empty."; + } else { + EffectField* field = nullptr; - effect_file.close(); - } else { - qCritical() << "Failed to open effect file" << em->filename; - } - } - } + switch (type) { + case EffectField::EFFECT_FIELD_DOUBLE: + { + + DoubleField* double_field = new DoubleField(row, id); + + for (int i=0;iSetDefault(attr.value().toDouble()); + } else if (attr.name() == "min") { + double_field->SetMinimum(attr.value().toDouble()); + } else if (attr.name() == "max") { + double_field->SetMaximum(attr.value().toDouble()); + } + } + + field = double_field; + } + break; + case EffectField::EFFECT_FIELD_COLOR: + { + QColor color; + + field = new ColorField(row, id); + + for (int i=0;iSetValueAt(0, color); + } + break; + case EffectField::EFFECT_FIELD_STRING: + field = new StringField(row, id); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; + case EffectField::EFFECT_FIELD_BOOL: + field = new BoolField(row, id); + for (int i=0;iSetValueAt(0, attr.value() == "1"); + } + } + break; + case EffectField::EFFECT_FIELD_COMBO: + { + ComboField* combo_field = new ComboField(row, id); + int combo_default_index = 0; + for (int i=0;iAddItem(reader.text().toString(), combo_item_count); + combo_item_count++; + } + } + combo_field->SetValueAt(0, combo_default_index); + field = combo_field; + } + break; + case EffectField::EFFECT_FIELD_FONT: + field = new FontField(row, id); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; + case EffectField::EFFECT_FIELD_FILE: + field = new FileField(row, id); + for (int i=0;iSetValueAt(0, attr.value().toString()); + } + } + break; + } + + if (field != nullptr) { + connect(field, SIGNAL(changed()), this, SLOT(field_changed())); + } + } + } + } + } + } else if (reader.name() == "shader" && reader.isStartElement()) { + SetFlags(Flags() & ShaderFlag); + const QXmlStreamAttributes& attributes = reader.attributes(); + for (int i=0;ifilename; + enable_superimpose = false; + } + break; + } + } + }*/ + reader.readNext(); + } + + effect_file.close(); + } else { + qCritical() << "Failed to open effect file" << em->filename; + } + } + } } Effect::~Effect() { - if (isOpen) { - close(); - } + if (isOpen) { + close(); + } - delete container; + delete container; - for (int i=0;irows.at(i); - copy_row->setKeyframing(row->isKeyframing()); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - EffectField* copy_field = copy_row->field(j); - copy_field->keyframes = field->keyframes; - copy_field->set_current_data(field->get_current_data()); - } - } + for (int i=0;irows.at(i); + copy_row->setKeyframing(row->isKeyframing()); + for (int j=0;jfieldCount();j++) { + // Get field from this (the source) effect + EffectField* field = row->field(j); + + // Get field from the destination effect + EffectField* copy_field = copy_row->field(j); + + // Copy keyframes between effects + copy_field->keyframes = field->keyframes; + } + } } EffectRow* Effect::add_row(const QString& name, bool savable, bool keyframable) { - EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); - rows.append(row); - return row; + EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); + rows.append(row); + return row; } EffectRow* Effect::row(int i) { - return rows.at(i); + return rows.at(i); } int Effect::row_count() { - return rows.size(); + return rows.size(); } EffectGizmo *Effect::add_gizmo(int type) { - EffectGizmo* gizmo = new EffectGizmo(type); - gizmos.append(gizmo); - return gizmo; + EffectGizmo* gizmo = new EffectGizmo(type); + gizmos.append(gizmo); + return gizmo; } EffectGizmo *Effect::gizmo(int i) { - return gizmos.at(i); + return gizmos.at(i); } int Effect::gizmo_count() { - return gizmos.size(); + return gizmos.size(); } void Effect::refresh() {} void Effect::field_changed() { - panel_sequence_viewer->viewer_widget->frame_update(); - panel_graph_editor->update_panel(); + panel_sequence_viewer->viewer_widget->frame_update(); + panel_graph_editor->update_panel(); } void Effect::show_context_menu(const QPoint& pos) { - if (meta->type == EFFECT_TYPE_EFFECT) { + if (meta->type == EFFECT_TYPE_EFFECT) { QMenu menu(olive::MainWindow); - int index = get_index_in_clip(); + int index = get_index_in_clip(); - menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); - menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); + menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); + menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); - panel_effect_controls->add_effect_paste_action(&menu); + panel_effect_controls->add_effect_paste_action(&menu); - menu.addSeparator(); + menu.addSeparator(); - if (index > 0) { - menu.addAction(tr("Move &Up"), this, SLOT(move_up())); - } + if (index > 0) { + menu.addAction(tr("Move &Up"), this, SLOT(move_up())); + } - if (index < parent_clip->effects.size() - 1) { - menu.addAction(tr("Move &Down"), this, SLOT(move_down())); - } + if (index < parent_clip->effects.size() - 1) { + menu.addAction(tr("Move &Down"), this, SLOT(move_down())); + } - menu.addSeparator(); + menu.addSeparator(); - menu.addAction(tr("D&elete"), this, SLOT(delete_self())); + menu.addAction(tr("D&elete"), this, SLOT(delete_self())); - menu.addSeparator(); + menu.addSeparator(); - menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); + menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); - menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); + menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); - menu.exec(container->title_bar->mapToGlobal(pos)); - } + menu.exec(container->title_bar->mapToGlobal(pos)); + } } void Effect::delete_self() { - EffectDeleteCommand* command = new EffectDeleteCommand(); - command->clips.append(parent_clip); - command->fx.append(get_index_in_clip()); - olive::UndoStack.push(command); - update_ui(true); + EffectDeleteCommand* command = new EffectDeleteCommand(); + command->clips.append(parent_clip); + command->fx.append(get_index_in_clip()); + olive::UndoStack.push(command); + update_ui(true); } void Effect::move_up() { - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = get_index_in_clip(); - command->to = command->from - 1; - olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); - panel_sequence_viewer->viewer_widget->frame_update(); + MoveEffectCommand* command = new MoveEffectCommand(); + command->clip = parent_clip; + command->from = get_index_in_clip(); + command->to = command->from - 1; + olive::UndoStack.push(command); + panel_effect_controls->reload_clips(); + panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::move_down() { - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = get_index_in_clip(); - command->to = command->from + 1; - olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); - panel_sequence_viewer->viewer_widget->frame_update(); + MoveEffectCommand* command = new MoveEffectCommand(); + command->clip = parent_clip; + command->from = get_index_in_clip(); + command->to = command->from + 1; + olive::UndoStack.push(command); + panel_effect_controls->reload_clips(); + panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::save_to_file() { - // save effect settings to file + // save effect settings to file QString file = QFileDialog::getSaveFileName(olive::MainWindow, - tr("Save Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + tr("Save Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); - // if the user picked a file - if (!file.isEmpty()) { + // if the user picked a file + if (!file.isEmpty()) { // ensure file ends with .xml extension if (!file.endsWith(".xml", Qt::CaseInsensitive)) { file.append(".xml"); } - QFile file_handle(file); - if (file_handle.open(QFile::WriteOnly)) { + QFile file_handle(file); + if (file_handle.open(QFile::WriteOnly)) { - file_handle.write(save_to_string()); + file_handle.write(save_to_string()); - file_handle.close(); - } else { + file_handle.close(); + } else { QMessageBox::critical(olive::MainWindow, - tr("Save Settings Failed"), - tr("Failed to open \"%1\" for writing.").arg(file), - QMessageBox::Ok); - } - } + tr("Save Settings Failed"), + tr("Failed to open \"%1\" for writing.").arg(file), + QMessageBox::Ok); + } + } } void Effect::load_from_file() { - // load effect settings from file + // load effect settings from file QString file = QFileDialog::getOpenFileName(olive::MainWindow, - tr("Load Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + tr("Load Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); - // if the user picked a file - if (!file.isEmpty()) { - QFile file_handle(file); - if (file_handle.open(QFile::ReadOnly)) { + // if the user picked a file + if (!file.isEmpty()) { + QFile file_handle(file); + if (file_handle.open(QFile::ReadOnly)) { olive::UndoStack.push(new SetEffectData(EffectPtr(this), file_handle.readAll())); - file_handle.close(); + file_handle.close(); - update_ui(false); - } else { + update_ui(false); + } else { QMessageBox::critical(olive::MainWindow, - tr("Load Settings Failed"), - tr("Failed to open \"%1\" for reading.").arg(file), - QMessageBox::Ok); - } - } + tr("Load Settings Failed"), + tr("Failed to open \"%1\" for reading.").arg(file), + QMessageBox::Ok); + } + } +} + +bool Effect::AlwaysUpdate() +{ + return enable_always_update_; +} + +void Effect::SetAlwaysUpdate(bool b) +{ + enable_always_update_ = b; } int Effect::get_index_in_clip() { - if (parent_clip != nullptr) { - for (int i=0;ieffects.size();i++) { + if (parent_clip != nullptr) { + for (int i=0;ieffects.size();i++) { if (parent_clip->effects.at(i).get() == this) { - return i; - } - } - } - return -1; + return i; + } + } + } + return -1; } bool Effect::is_enabled() { - return container->enabled_check->isChecked(); + return container->enabled_check->isChecked(); } void Effect::set_enabled(bool b) { - container->enabled_check->setChecked(b); -} - -QVariant load_data_from_string(int type, const QString& string) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return string.toDouble(); - case EFFECT_FIELD_COLOR: return QColor(string); - case EFFECT_FIELD_BOOL: return (string == "1"); - case EFFECT_FIELD_COMBO: return string.toInt(); - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - return string; - } - return QVariant(); -} - -QString save_data_to_string(int type, const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); - case EFFECT_FIELD_COLOR: return data.value().name(); - case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); - case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - return data.toString(); - } - return QString(); + container->enabled_check->setChecked(b); } void Effect::load(QXmlStreamReader& stream) { - int row_count = 0; + int row_count = 0; - QString tag = stream.name().toString(); + QString tag = stream.name().toString(); - while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { - stream.readNext(); - if (stream.name() == "row" && stream.isStartElement()) { - if (row_count < rows.size()) { - EffectRow* row = rows.at(row_count); - int field_count = 0; + while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { + stream.readNext(); + if (stream.name() == "row" && stream.isStartElement()) { + if (row_count < rows.size()) { + EffectRow* row = rows.at(row_count); + int field_count = 0; - while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { - stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { + stream.readNext(); - // read field - if (stream.name() == "field" && stream.isStartElement()) { - if (field_count < row->fieldCount()) { - // match field using ID - int field_number = field_count; - for (int k=0;kfieldCount();l++) { - if (row->field(l)->id == attr.value()) { - field_number = l; -// qInfo() << "Found field by ID"; - break; - } - } - break; - } - } + // read field + if (stream.name() == "field" && stream.isStartElement()) { + if (field_count < row->fieldCount()) { + // match field using ID + int field_number = field_count; + for (int k=0;kfieldCount();l++) { + if (row->field(l)->id() == attr.value()) { + field_number = l; + break; + } + } + break; + } + } - EffectField* field = row->field(field_number); + EffectField* field = row->field(field_number); - // get current field value - for (int k=0;kset_current_data(load_data_from_string(field->type, attr.value().toString())); - break; - } - } + // get current field value + /* + for (int k=0;kSetCurrentValue(field->GetValueFromString(attr.value().toString())); + break; + } + } + */ - while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { - stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { + stream.readNext(); - // read keyframes - if (stream.name() == "key" && stream.isStartElement()) { - row->setKeyframing(true); + // read keyframes + if (stream.name() == "key" && stream.isStartElement()) { + row->setKeyframing(true); - EffectKeyframe key; - for (int k=0;ktype, 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 { - qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; - } - field_count++; - } - } + EffectKeyframe key; + for (int k=0;kConvertStringToValue(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 { + qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; + } + field_count++; + } + } - } else { - qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; - } - row_count++; - } else if (stream.isStartElement()) { - custom_load(stream); - } - } + } else { + qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; + } + row_count++; + } else if (stream.isStartElement()) { + custom_load(stream); + } + } } void Effect::custom_load(QXmlStreamReader &) {} void Effect::save(QXmlStreamWriter& stream) { - stream.writeAttribute("name", meta->category + "/" + meta->name); - stream.writeAttribute("enabled", QString::number(is_enabled())); + stream.writeAttribute("name", meta->category + "/" + meta->name); + stream.writeAttribute("enabled", QString::number(is_enabled())); - for (int i=0;isavable) { - stream.writeStartElement("row"); // row - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - stream.writeStartElement("field"); // field - stream.writeAttribute("id", field->id); - stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data())); - for (int k=0;kkeyframes.size();k++) { - const EffectKeyframe& key = field->keyframes.at(k); - stream.writeStartElement("key"); - stream.writeAttribute("value", save_data_to_string(field->type, key.data)); - stream.writeAttribute("frame", QString::number(key.time)); - stream.writeAttribute("type", QString::number(key.type)); - stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); - stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); - stream.writeAttribute("posthx", QString::number(key.post_handle_x)); - stream.writeAttribute("posthy", QString::number(key.post_handle_y)); - stream.writeEndElement(); // key - } - stream.writeEndElement(); // field - } - stream.writeEndElement(); // row - } - } + for (int i=0;isavable) { + stream.writeStartElement("row"); // row + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + stream.writeStartElement("field"); // field + stream.writeAttribute("id", field->id()); + for (int k=0;kkeyframes.size();k++) { + const EffectKeyframe& key = field->keyframes.at(k); + stream.writeStartElement("key"); + stream.writeAttribute("value", field->ConvertValueToString(key.data)); + stream.writeAttribute("frame", QString::number(key.time)); + stream.writeAttribute("type", QString::number(key.type)); + stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); + stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); + stream.writeAttribute("posthx", QString::number(key.post_handle_x)); + stream.writeAttribute("posthy", QString::number(key.post_handle_y)); + stream.writeEndElement(); // key + } + stream.writeEndElement(); // field + } + stream.writeEndElement(); // row + } + } } void Effect::load_from_string(const QByteArray &s) { - // clear existing keyframe data - for (int i=0;isetKeyframing(false); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - field->keyframes.clear(); - } - } + // clear existing keyframe data + for (int i=0;isetKeyframing(false); + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + field->keyframes.clear(); + } + } - // write settings with xml writer - QXmlStreamReader stream(s); + // write settings with xml writer + QXmlStreamReader stream(s); - while (!stream.atEnd()) { - stream.readNext(); + while (!stream.atEnd()) { + stream.readNext(); - // find the effect opening tag - if (stream.name() == "effect" && stream.isStartElement()) { + // find the effect opening tag + if (stream.name() == "effect" && stream.isStartElement()) { - // check the name to see if it matches this effect - const QXmlStreamAttributes& attributes = stream.attributes(); - for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; - QList effects_paths = get_effects_paths(); - const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; - for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; + QList effects_paths = get_effects_paths(); + const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; + for (int i=0;iaddShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { - qInfo() << "Vertex shader added successfully"; - } else { - glsl_compiled = false; - qWarning() << "Vertex shader could not be added"; - } - } - if (!fragPath.isEmpty()) { - if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { - qInfo() << "Fragment shader added successfully"; - } else { - glsl_compiled = false; - qWarning() << "Fragment shader could not be added"; - } - } - if (glsl_compiled) { - if (glslProgram->link()) { - qInfo() << "Shader program linked successfully"; - } else { - qWarning() << "Shader program failed to link"; - } - } - isOpen = true; - } - } else { - isOpen = true; - } + if (isOpen) { + qWarning() << "Tried to open an effect that was already open"; + close(); + } + if (olive::CurrentRuntimeConfig.shaders_are_enabled && (Flags() & ShaderFlag)) { + if (QOpenGLContext::currentContext() == nullptr) { + qWarning() << "No current context to create a shader program for - will retry next repaint"; + } else { + glslProgram = new QOpenGLShaderProgram(); + validate_meta_path(); + bool glsl_compiled = true; + if (!vertPath.isEmpty()) { + if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { + qInfo() << "Vertex shader added successfully"; + } else { + glsl_compiled = false; + qWarning() << "Vertex shader could not be added"; + } + } + if (!fragPath.isEmpty()) { + if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { + qInfo() << "Fragment shader added successfully"; + } else { + glsl_compiled = false; + qWarning() << "Fragment shader could not be added"; + } + } + if (glsl_compiled) { + if (glslProgram->link()) { + qInfo() << "Shader program linked successfully"; + } else { + qWarning() << "Shader program failed to link"; + } + } + isOpen = true; + } + } else { + isOpen = true; + } } void Effect::close() { - if (!isOpen) { - qWarning() << "Tried to close an effect that was already closed"; - } - delete_texture(); - if (glslProgram != nullptr) { - delete glslProgram; - glslProgram = nullptr; - } - isOpen = false; + if (!isOpen) { + qWarning() << "Tried to close an effect that was already closed"; + } + delete_texture(); + if (glslProgram != nullptr) { + delete glslProgram; + glslProgram = nullptr; + } + isOpen = false; } bool Effect::is_glsl_linked() { - return glslProgram != nullptr && glslProgram->isLinked(); + return glslProgram != nullptr && glslProgram->isLinked(); } void Effect::startEffect() { - if (!isOpen) { - open(); - qWarning() << "Tried to start a closed effect - opening"; - } - if (olive::CurrentRuntimeConfig.shaders_are_enabled - && enable_shader - && glslProgram->isLinked()) { - bound = glslProgram->bind(); - } + if (!isOpen) { + open(); + qWarning() << "Tried to start a closed effect - opening"; + } + if (olive::CurrentRuntimeConfig.shaders_are_enabled + && (Flags() & Effect::ShaderFlag) + && glslProgram->isLinked()) { + bound = glslProgram->bind(); + } } void Effect::endEffect() { - if (bound) glslProgram->release(); - bound = false; + if (bound) glslProgram->release(); + bound = false; +} + +int Effect::Flags() +{ + return flags_; +} + +void Effect::SetFlags(int flags) +{ + flags_ = flags; } int Effect::getIterations() { - return iterations; + return iterations; } void Effect::setIterations(int i) { - iterations = i; + iterations = i; } void Effect::process_image(double, uint8_t *, uint8_t *, int){} EffectPtr Effect::copy(Clip *c) { EffectPtr copy = Effect::Create(c, meta); - copy->set_enabled(is_enabled()); - copy_field_keyframes(copy); - return copy; + copy->set_enabled(is_enabled()); + copy_field_keyframes(copy); + return copy; } void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { glslProgram->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); - glslProgram->setUniformValue("time", GLfloat(timecode)); - glslProgram->setUniformValue("iteration", iteration); + glslProgram->setUniformValue("time", GLfloat(timecode)); + glslProgram->setUniformValue("iteration", iteration); - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - glslProgram->setUniformValue(field->id.toUtf8().constData(), GLfloat(field->get_double_value(timecode))); - break; - case EFFECT_FIELD_COLOR: - glslProgram->setUniformValue( - field->id.toUtf8().constData(), - GLfloat(field->get_color_value(timecode).redF()), - GLfloat(field->get_color_value(timecode).greenF()), - GLfloat(field->get_color_value(timecode).blueF()) - ); - break; - case EFFECT_FIELD_STRING: break; // can you even send a string to a uniform value? - case EFFECT_FIELD_BOOL: - glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_bool_value(timecode)); - break; - case EFFECT_FIELD_COMBO: - glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_combo_index(timecode)); - break; - case EFFECT_FIELD_FONT: break; // can you even send a string to a uniform value? - case EFFECT_FIELD_FILE: break; // can you even send a string to a uniform value? - } - } - } - } + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id().isEmpty()) { + switch (field->type()) { + case EffectField::EFFECT_FIELD_DOUBLE: + { + DoubleField* double_field = static_cast(field); + glslProgram->setUniformValue(double_field->id().toUtf8().constData(), + GLfloat(double_field->GetDoubleAt(timecode))); + } + break; + case EffectField::EFFECT_FIELD_COLOR: + { + ColorField* color_field = static_cast(field); + glslProgram->setUniformValue( + color_field->id().toUtf8().constData(), + GLfloat(color_field->GetColorAt(timecode).redF()), + GLfloat(color_field->GetColorAt(timecode).greenF()), + GLfloat(color_field->GetColorAt(timecode).blueF()) + ); + } + break; + case EffectField::EFFECT_FIELD_BOOL: + glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toBool()); + break; + case EffectField::EFFECT_FIELD_COMBO: + glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); + break; + + // can you even send a string to a uniform value? + case EffectField::EFFECT_FIELD_STRING: + case EffectField::EFFECT_FIELD_FONT: + case EffectField::EFFECT_FIELD_FILE: + break; + } + } + } + } } void Effect::process_coords(double, GLTextureCoords&, int) {} GLuint Effect::process_superimpose(double timecode) { - bool dimensions_changed = false; - bool redrew_image = false; + bool dimensions_changed = false; + bool redrew_image = false; int width = parent_clip->media_width(); int height = parent_clip->media_height(); - if (width != img.width() || height != img.height()) { - img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); - dimensions_changed = true; - } + if (width != img.width() || height != img.height()) { + img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); + dimensions_changed = true; + } - if (valueHasChanged(timecode) || dimensions_changed || enable_always_update) { - redraw(timecode); - redrew_image = true; - } + if (valueHasChanged(timecode) || dimensions_changed || AlwaysUpdate()) { + redraw(timecode); + redrew_image = true; + } - if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { - delete_texture(); + if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { + delete_texture(); - texture = new QOpenGLTexture(QOpenGLTexture::Target2D); - texture->setSize(img.width(), img.height()); - texture->setFormat(QOpenGLTexture::RGBA8_UNorm); - texture->setMipLevels(texture->maximumMipLevels()); - texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); - texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); + texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + texture->setSize(img.width(), img.height()); + texture->setFormat(QOpenGLTexture::RGBA8_UNorm); + texture->setMipLevels(texture->maximumMipLevels()); + texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); - redrew_image = true; - } + redrew_image = true; + } - if (redrew_image) { - texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); - } + if (redrew_image) { + texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); + } - return texture->textureId(); + return texture->textureId(); } void Effect::process_audio(double, double, quint8*, int, int) {} @@ -942,158 +968,161 @@ void Effect::process_audio(double, double, quint8*, int, int) {} void Effect::gizmo_draw(double, GLTextureCoords &) {} void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) { - for (int i=0;ix_field1 != nullptr) { - 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); - } - if (gizmo->y_field1 != nullptr) { - 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); - } - if (gizmo->x_field2 != nullptr) { - 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); - } - if (gizmo->y_field2 != nullptr) { - 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); - } - if (done) olive::UndoStack.push(ca); - break; - } - } + for (int i=0;ix_field1 != nullptr) { + gizmo->x_field1->SetValueAt(timecode, gizmo->x_field1->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi1); + //gizmo->x_field1->make_key_from_change(ca); + } + if (gizmo->y_field1 != nullptr) { + gizmo->y_field1->SetValueAt(timecode, gizmo->y_field1->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi1); + //gizmo->y_field1->make_key_from_change(ca); + } + if (gizmo->x_field2 != nullptr) { + gizmo->x_field2->SetValueAt(timecode, gizmo->x_field2->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi2); + //gizmo->x_field2->make_key_from_change(ca); + } + if (gizmo->y_field2 != nullptr) { + gizmo->y_field2->SetValueAt(timecode, gizmo->y_field2->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi2); + //gizmo->y_field2->make_key_from_change(ca); + } + if (done) olive::UndoStack.push(ca); + break; + } + } } void Effect::gizmo_world_to_screen() { - GLfloat view_val[16]; - GLfloat projection_val[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, view_val); - glGetFloatv(GL_PROJECTION_MATRIX, projection_val); + GLfloat view_val[16]; + GLfloat projection_val[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, view_val); + glGetFloatv(GL_PROJECTION_MATRIX, projection_val); - QMatrix4x4 view_matrix(view_val); - QMatrix4x4 projection_matrix(projection_val); + QMatrix4x4 view_matrix(view_val); + QMatrix4x4 projection_matrix(projection_val); - for (int i=0;iget_point_count();j++) { - QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); + for (int j=0;jget_point_count();j++) { + QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); - int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); - int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); + int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); + int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); - g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1); - } - } + g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1); + } + } } bool Effect::are_gizmos_enabled() { - return (gizmos.size() > 0); + return (gizmos.size() > 0); } void Effect::redraw(double) { - /* - // run javascript - QPainter p(&img); - painter_wrapper.img = &img; - painter_wrapper.painter = &p; + /* + // run javascript + QPainter p(&img); + painter_wrapper.img = &img; + painter_wrapper.painter = &p; - jsEngine.globalObject().setProperty("painter", wrapper_obj); + jsEngine.globalObject().setProperty("painter", wrapper_obj); jsEngine.globalObject().setProperty("width", parent_clip->media_width()); jsEngine.globalObject().setProperty("height", parent_clip->media_height()); - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); - break; - case EFFECT_FIELD_COLOR: - jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); - break; - case EFFECT_FIELD_STRING: - jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); - break; - case EFFECT_FIELD_BOOL: - jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); - break; - case EFFECT_FIELD_COMBO: - jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); - break; - case EFFECT_FIELD_FONT: - jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); - break; - } - } - } - } + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id.isEmpty()) { + switch (field->type) { + case EFFECT_FIELD_DOUBLE: + jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); + break; + case EFFECT_FIELD_COLOR: + jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); + break; + case EFFECT_FIELD_STRING: + jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); + break; + case EFFECT_FIELD_BOOL: + jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); + break; + case EFFECT_FIELD_COMBO: + jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); + break; + case EFFECT_FIELD_FONT: + jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); + break; + } + } + } + } - jsEngine.evaluate(script); - */ + jsEngine.evaluate(script); + */ } bool Effect::valueHasChanged(double timecode) { - if (cachedValues.size() == 0) { - for (int i=0;ifieldCount();j++) { - cachedValues.append(crow->field(j)->get_current_data()); - } - } - return true; - } else { - bool changed = false; - int index = 0; - for (int i=0;ifieldCount();j++) { - EffectField* field = crow->field(j); - field->validate_keyframe_data(timecode); - if (cachedValues.at(index) != field->get_current_data()) { - changed = true; - } - cachedValues[index] = field->get_current_data(); - index++; - } - } - return changed; - } + if (cachedValues.size() == 0) { + + for (int i=0;ifieldCount();j++) { + cachedValues.append(crow->field(j)->GetValueAt(timecode)); + } + } + return true; + + } else { + + bool changed = false; + int index = 0; + for (int i=0;ifieldCount();j++) { + EffectField* field = crow->field(j); + if (cachedValues.at(index) != field->GetValueAt(timecode)) { + changed = true; + } + cachedValues[index] = field->GetValueAt(timecode); + index++; + } + } + return changed; + + } } void Effect::delete_texture() { - if (texture != nullptr) { - delete texture; - texture = nullptr; - } + if (texture != nullptr) { + delete texture; + texture = nullptr; + } } const EffectMeta* get_meta_from_name(const QString& input) { - int split_index = input.indexOf('/'); - QString category; - if (split_index > -1) { - category = input.left(split_index); - } - QString name = input.mid(split_index + 1); + int split_index = input.indexOf('/'); + QString category; + if (split_index > -1) { + category = input.left(split_index); + } + QString name = input.mid(split_index + 1); - for (int j=0;j(a) + static_cast(b); - mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); - return static_cast(mixed_sample); + qint32 mixed_sample = static_cast(a) + static_cast(b); + mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); + return static_cast(mixed_sample); } diff --git a/project/effect.h b/project/effect.h index 64224ec97..dea03233c 100644 --- a/project/effect.h +++ b/project/effect.h @@ -42,6 +42,9 @@ #include "ui/collapsiblewidget.h" #include "ui/checkboxex.h" +#include "effectfields.h" +#include "effectrow.h" +#include "effectgizmo.h" class Clip; @@ -94,36 +97,6 @@ enum EffectInternal { EFFECT_INTERNAL_COUNT }; -enum EffectBlendMode { - BLEND_MODE_ADD, - BLEND_MODE_AVERAGE, - BLEND_MODE_COLORBURN, - BLEND_MODE_COLORDODGE, - BLEND_MODE_DARKEN, - BLEND_MODE_DIFFERENCE, - BLEND_MODE_EXCLUSION, - BLEND_MODE_GLOW, - BLEND_MODE_HARDLIGHT, - BLEND_MODE_HARDMIX, - BLEND_MODE_LIGHTEN, - BLEND_MODE_LINEARBURN, - BLEND_MODE_LINEARDODGE, - BLEND_MODE_LINEARLIGHT, - BLEND_MODE_MULTIPLY, - BLEND_MODE_NEGATION, - BLEND_MODE_NORMAL, - BLEND_MODE_OVERLAY, - BLEND_MODE_PHOENIX, - BLEND_MODE_PINLIGHT, - BLEND_MODE_REFLECT, - BLEND_MODE_SCREEN, - BLEND_MODE_SOFTLIGHT, - BLEND_MODE_SUBSTRACT, - BLEND_MODE_SUBTRACT, - BLEND_MODE_VIVIDLIGHT, - BLEND_MODE_COUNT -}; - struct GLTextureCoords { int grid_size; @@ -161,10 +134,6 @@ const EffectMeta* get_meta_from_name(const QString& input); qint16 mix_audio_sample(qint16 a, qint16 b); -#include "effectfield.h" -#include "effectrow.h" -#include "effectgizmo.h" - class Effect : public QObject { Q_OBJECT public: @@ -207,10 +176,14 @@ public: virtual void startEffect(); virtual void endEffect(); - bool enable_shader; - bool enable_coords; - bool enable_superimpose; - bool enable_image; + enum VideoEffectFlags { + ShaderFlag = 0x1, + CoordsFlag = 0x2, + SuperimposeFlag = 0x4, + ImageFlag = 0x8 + }; + int Flags(); + void SetFlags(int flags); int getIterations(); void setIterations(int i); @@ -258,8 +231,9 @@ protected: QImage img; QOpenGLTexture* texture; - // enable effect to update constantly - bool enable_always_update; + bool AlwaysUpdate(); + void SetAlwaysUpdate(bool b); + private: // superimpose effect QString script; @@ -272,6 +246,11 @@ private: bool bound; int iterations; + int flags_; + + // enable effect to update constantly + bool enable_always_update_; + // superimpose functions virtual void redraw(double timecode); bool valueHasChanged(double timecode); diff --git a/project/effectfield.cpp b/project/effectfield.cpp deleted file mode 100644 index 5758bd4c8..000000000 --- a/project/effectfield.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "effectfield.h" - -#include "ui/labelslider.h" -#include "ui/colorbutton.h" -#include "ui/texteditex.h" -#include "ui/checkboxex.h" -#include "ui/comboboxex.h" -#include "ui/fontcombobox.h" -#include "ui/embeddedfilechooser.h" - -#include "io/config.h" - -#include "effectrow.h" -#include "effect.h" - -#include "project/undo.h" -#include "project/clip.h" -#include "project/sequence.h" - -#include "io/math.h" - -#include -#include - -#include "debug.h" - -EffectField::EffectField(EffectRow *parent, int t, const QString &i) : - parent_row(parent), - type(t), - id(i) -{ - switch (t) { - case EFFECT_FIELD_DOUBLE: - { - LabelSlider* ls = new LabelSlider(); - ui_element = ls; - connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change())); - connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked())); - } - break; - case EFFECT_FIELD_COLOR: - { - ColorButton* cb = new ColorButton(); - ui_element = cb; - connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_STRING: - { - TextEditEx* edit = new TextEditEx(); - - // TODO magic number 2 - i'm not sure how to make this work otherwise though - edit->setFixedHeight(qCeil(edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + edit->document()->documentMargin() + edit->document()->documentMargin() + 2)); - - edit->setUndoRedoEnabled(true); - ui_element = edit; - connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_BOOL: - { - CheckboxEx* cb = new CheckboxEx(); - ui_element = cb; - connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change())); - connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); - } - break; - case EFFECT_FIELD_COMBO: - { - ComboBoxEx* cb = new ComboBoxEx(); - ui_element = cb; - connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_FONT: - { - FontCombobox* fcb = new FontCombobox(); - ui_element = fcb; - connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_FILE: - { - EmbeddedFileChooser* efc = new EmbeddedFileChooser(); - ui_element = efc; - connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change())); - } - break; - } -} - -EffectField::~EffectField() {} - -double EffectField::get_validated_keyframe_handle(int key, bool post) { - int comp_key = -1; - - // find keyframe before or after this one - for (int i=0;i keyframes.at(key).time) == post) - && (comp_key == -1 - || ((keyframes.at(i).time < keyframes.at(comp_key).time) == post))) { - // compare with next keyframe for post or previous frame for pre - comp_key = i; - } - } - - double adjusted_key = post ? keyframes.at(key).post_handle_x : keyframes.at(key).pre_handle_x; - - // if this is the earliest/latest keyframe, no validation is required - if (comp_key == -1) { - return adjusted_key; - } - - double comp = keyframes.at(comp_key).time - keyframes.at(key).time; - - // if comp keyframe is bezier, validate with its accompanying handle - if (keyframes.at(comp_key).type == EFFECT_KEYFRAME_BEZIER) { - double relative_comp_handle = comp + (post ? keyframes.at(comp_key).pre_handle_x : keyframes.at(comp_key).post_handle_x); - // return an average - if ((post && keyframes.at(key).post_handle_x > relative_comp_handle) - || (!post && keyframes.at(key).pre_handle_x < relative_comp_handle)) { - adjusted_key = (adjusted_key + relative_comp_handle)*0.5; - } - } - - // don't let handle go beyond the compare keyframe's time - if (post == (adjusted_key > comp)) { - return comp; - } - - if (post == (adjusted_key < 0)) { - return 0; - } - - // original value is valid - return adjusted_key; -} - -QVariant EffectField::get_previous_data() { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_BOOL: return !static_cast(ui_element)->isChecked(); - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->getPreviousIndex(); - case EFFECT_FIELD_FONT: return static_cast(ui_element)->getPreviousValue(); - case EFFECT_FIELD_FILE: return static_cast(ui_element)->getPreviousValue(); - } - return QVariant(); -} - -QVariant EffectField::get_current_data() { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->value(); - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->get_color(); - case EFFECT_FIELD_STRING: return static_cast(ui_element)->getPlainTextEx(); - case EFFECT_FIELD_BOOL: return static_cast(ui_element)->isChecked(); - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->currentIndex(); - case EFFECT_FIELD_FONT: return static_cast(ui_element)->currentText(); - case EFFECT_FIELD_FILE: return static_cast(ui_element)->getFilename(); - } - return QVariant(); -} - -double EffectField::frameToTimecode(long frame) { - return (double(frame) / parent_row->parent_effect->parent_clip->sequence->frame_rate); -} - -long EffectField::timecodeToFrame(double timecode) { - return qRound(timecode * parent_row->parent_effect->parent_clip->sequence->frame_rate); -} - -void EffectField::set_current_data(const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return static_cast(ui_element)->set_value(data.toDouble(), false); - case EFFECT_FIELD_COLOR: return static_cast(ui_element)->set_color(data.value()); - case EFFECT_FIELD_STRING: return static_cast(ui_element)->setPlainTextEx(data.toString()); - case EFFECT_FIELD_BOOL: return static_cast(ui_element)->setChecked(data.toBool()); - case EFFECT_FIELD_COMBO: return static_cast(ui_element)->setCurrentIndexEx(data.toInt()); - case EFFECT_FIELD_FONT: return static_cast(ui_element)->setCurrentTextEx(data.toString()); - case EFFECT_FIELD_FILE: return static_cast(ui_element)->setFilename(data.toString()); - } -} - -void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { - int before_keyframe_index = -1; - int after_keyframe_index = -1; - long before_keyframe_time = LONG_MIN; - long after_keyframe_time = LONG_MAX; - long frame = timecodeToFrame(timecode); - - for (int i=0;i before_keyframe_time) { - before_keyframe_index = i; - before_keyframe_time = eval_keyframe_time; - } else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) { - after_keyframe_index = i; - after_keyframe_time = eval_keyframe_time; - } - } - - if ((type == EFFECT_FIELD_DOUBLE || type == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) { - // interpolate - before = before_keyframe_index; - after = after_keyframe_index; - progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); - } else if (before_keyframe_index > -1) { - before = before_keyframe_index; - after = before_keyframe_index; - } else { - before = after_keyframe_index; - after = after_keyframe_index; - } -} - -bool EffectField::hasKeyframes() { - return (parent_row->isKeyframing() && keyframes.size() > 0); -} - -QVariant EffectField::validate_keyframe_data(double timecode, bool async) { - if (hasKeyframes()) { - int before_keyframe; - int after_keyframe; - double progress; - get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); - - const QVariant& before_data = keyframes.at(before_keyframe).data; - switch (type) { - case EFFECT_FIELD_DOUBLE: - { - double value; - 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); - - double before_dbl = before_key.data.toDouble(); - double after_dbl = after_key.data.toDouble(); - - if (before_key.type == EFFECT_KEYFRAME_HOLD) { - // hold - value = before_dbl; - } else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) { - // bezier interpolation - if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { - // cubic bezier - double t = cubic_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+get_validated_keyframe_handle(before_keyframe, true), after_key.time+get_validated_keyframe_handle(after_keyframe, false), 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); - } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier - // 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+get_validated_keyframe_handle(before_keyframe, true), after_key.time); - value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t); - } else { - // this keyframe is the bezier one - double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+get_validated_keyframe_handle(after_keyframe, false), after_key.time); - value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t); - } - } else { - // linear - value = double_lerp(before_dbl, after_dbl, progress); - } - } - if (async) { - return value; - } - static_cast(ui_element)->set_value(value, false); - } - break; - case EFFECT_FIELD_COLOR: - { - QColor value; - if (before_keyframe == after_keyframe) { - value = keyframes.at(before_keyframe).data.value(); - } else { - QColor before_data = keyframes.at(before_keyframe).data.value(); - QColor after_data = keyframes.at(after_keyframe).data.value(); - 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; - } - static_cast(ui_element)->set_color(value); - } - break; - case EFFECT_FIELD_STRING: - if (async) { - return before_data; - } - static_cast(ui_element)->setPlainTextEx(before_data.toString()); - break; - case EFFECT_FIELD_BOOL: - if (async) { - return before_data; - } - static_cast(ui_element)->setChecked(before_data.toBool()); - break; - case EFFECT_FIELD_COMBO: - if (async) { - return before_data; - } - static_cast(ui_element)->setCurrentIndexEx(before_data.toInt()); - break; - case EFFECT_FIELD_FONT: - if (async) { - return before_data; - } - static_cast(ui_element)->setCurrentTextEx(before_data.toString()); - break; - case EFFECT_FIELD_FILE: - if (async) { - return before_data; - } - static_cast(ui_element)->setFilename(before_data.toString()); - break; - } - } - return QVariant(); -} - -void EffectField::ui_element_change() { - bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); - ComboAction* ca = nullptr; - if (!dragging_double) ca = new ComboAction(); - make_key_from_change(ca); - if (!dragging_double) olive::UndoStack.push(ca); - emit changed(); -} - -void EffectField::make_key_from_change(ComboAction* ca) { - if (parent_row->isKeyframing()) { - parent_row->set_keyframe_now(ca); - } else if (ca != nullptr) { - // set undo - ca->append(new EffectFieldUndo(this)); - } -} - -QWidget* EffectField::get_ui_element() { - return ui_element; -} - -bool EffectField::is_enabled() { - return ui_element->isEnabled(); -} - -void EffectField::set_enabled(bool e) { - ui_element->setEnabled(e); -} - -double EffectField::get_double_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toDouble(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->value(); -} - -void EffectField::set_double_value(double v) { - static_cast(ui_element)->set_value(v, false); -} - -void EffectField::set_double_default_value(double v) { - static_cast(ui_element)->set_default_value(v); -} - -void EffectField::set_double_minimum_value(double v) { - static_cast(ui_element)->set_minimum_value(v); -} - -void EffectField::set_double_maximum_value(double v) { - static_cast(ui_element)->set_maximum_value(v); -} - -void EffectField::add_combo_item(const QString& name, const QVariant& data) { - static_cast(ui_element)->addItem(name, data); -} - -int EffectField::get_combo_index(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toInt(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentIndex(); -} - -QVariant EffectField::get_combo_data(double timecode) { - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentData(); -} - -QString EffectField::get_combo_string(double timecode) { - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentText(); -} - -void EffectField::set_combo_index(int index) { - static_cast(ui_element)->setCurrentIndexEx(index); -} - -void EffectField::set_combo_string(const QString& s) { - static_cast(ui_element)->setCurrentTextEx(s); -} - -bool EffectField::get_bool_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toBool(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->isChecked(); -} - -void EffectField::set_bool_value(bool b) { - return static_cast(ui_element)->setChecked(b); -} - -QString EffectField::get_string_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->getPlainTextEx(); -} - -void EffectField::set_string_value(const QString& s) { - static_cast(ui_element)->setPlainTextEx(s); -} - -QString EffectField::get_font_name(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->currentText(); -} - -void EffectField::set_font_name(const QString& s) { - static_cast(ui_element)->setCurrentText(s); -} - -QColor EffectField::get_color_value(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).value(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->get_color(); -} - -void EffectField::set_color_value(QColor color) { - static_cast(ui_element)->set_color(color); -} - -QString EffectField::get_filename(double timecode, bool async) { - if (async && hasKeyframes()) { - return validate_keyframe_data(timecode, true).toString(); - } - validate_keyframe_data(timecode); - return static_cast(ui_element)->getFilename(); -} - -void EffectField::set_filename(const QString &s) { - static_cast(ui_element)->setFilename(s); -} diff --git a/project/effectfield.h b/project/effectfield.h deleted file mode 100644 index 4818d5538..000000000 --- a/project/effectfield.h +++ /dev/null @@ -1,108 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef EFFECTFIELD_H -#define EFFECTFIELD_H - -enum EffectFieldType { - EFFECT_FIELD_DOUBLE, - EFFECT_FIELD_COLOR, - EFFECT_FIELD_STRING, - EFFECT_FIELD_BOOL, - EFFECT_FIELD_COMBO, - EFFECT_FIELD_FONT, - EFFECT_FIELD_FILE -}; - -#include -#include -#include - -#include "keyframe.h" - -class EffectRow; -class ComboAction; - -class EffectField : public QObject { - Q_OBJECT -public: - EffectField(EffectRow* parent, int t, const QString& i); - ~EffectField(); - - EffectRow* parent_row; - int type; - QString id; - - double get_validated_keyframe_handle(int key, bool post); - - QVariant get_previous_data(); - QVariant get_current_data(); - double frameToTimecode(long frame); - long timecodeToFrame(double timecode); - void set_current_data(const QVariant&); - void get_keyframe_data(double timecode, int& before, int& after, double& d); - QVariant validate_keyframe_data(double timecode, bool async = false); - - double get_double_value(double timecode, bool async = false); - void set_double_value(double v); - void set_double_default_value(double v); - void set_double_minimum_value(double v); - void set_double_maximum_value(double v); - - QString get_string_value(double timecode, bool async = false); - void set_string_value(const QString &s); - - void add_combo_item(const QString& name, const QVariant &data); - int get_combo_index(double timecode, bool async = false); - QVariant get_combo_data(double timecode); - QString get_combo_string(double timecode); - void set_combo_index(int index); - void set_combo_string(const QString& s); - - bool get_bool_value(double timecode, bool async = false); - void set_bool_value(bool b); - - QString get_font_name(double timecode, bool async = false); - void set_font_name(const QString& s); - - QColor get_color_value(double timecode, bool async = false); - void set_color_value(QColor color); - - QString get_filename(double timecode, bool async = false); - void set_filename(const QString& s); - - QWidget* get_ui_element(); - bool is_enabled(); - void set_enabled(bool e); - QVector keyframes; - QWidget* ui_element; - - void make_key_from_change(ComboAction* ca); -public slots: - void ui_element_change(); -private: - bool hasKeyframes(); -signals: - void changed(); - void toggled(bool); - void clicked(); -}; - -#endif // EFFECTFIELD_H diff --git a/project/effectfields.h b/project/effectfields.h new file mode 100644 index 000000000..668108ae6 --- /dev/null +++ b/project/effectfields.h @@ -0,0 +1,12 @@ +#ifndef EFFECTFIELDS_H +#define EFFECTFIELDS_H + +#include "effectfields/boolfield.h" +#include "effectfields/colorfield.h" +#include "effectfields/combofield.h" +#include "effectfields/doublefield.h" +#include "effectfields/filefield.h" +#include "effectfields/fontfield.h" +#include "effectfields/stringfield.h" + +#endif // EFFECTFIELDS_H diff --git a/project/effectfields/boolfield.cpp b/project/effectfields/boolfield.cpp new file mode 100644 index 000000000..e230c7ad7 --- /dev/null +++ b/project/effectfields/boolfield.cpp @@ -0,0 +1,20 @@ +#include "boolfield.h" + +BoolField::BoolField(EffectRow *parent, const QString &id) : + EffectField(parent, id, EFFECT_FIELD_BOOL) +{} + +bool BoolField::GetBoolAt(double timecode) +{ + return GetValueAt(timecode).toBool(); +} + +QVariant BoolField::ConvertStringToValue(const QString &s) +{ + return (s == "1"); +} + +QString BoolField::ConvertValueToString(const QVariant &v) +{ + return QString::number(v.toBool()); +} diff --git a/project/effectfields/boolfield.h b/project/effectfields/boolfield.h new file mode 100644 index 000000000..ee3fd848c --- /dev/null +++ b/project/effectfields/boolfield.h @@ -0,0 +1,18 @@ +#ifndef BOOLFIELD_H +#define BOOLFIELD_H + +#include "effectfield.h" + +class BoolField : public EffectField +{ + Q_OBJECT +public: + BoolField(EffectRow* parent, const QString& id); + + bool GetBoolAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // BOOLFIELD_H diff --git a/project/effectfields/colorfield.cpp b/project/effectfields/colorfield.cpp new file mode 100644 index 000000000..435c79ddc --- /dev/null +++ b/project/effectfields/colorfield.cpp @@ -0,0 +1,22 @@ +#include "colorfield.h" + +#include + +ColorField::ColorField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_COLOR) +{} + +QColor ColorField::GetColorAt(double timecode) +{ + return GetValueAt(timecode).value(); +} + +QVariant ColorField::ConvertStringToValue(const QString &s) +{ + return QColor(s); +} + +QString ColorField::ConvertValueToString(const QVariant &v) +{ + return v.value().name(); +} diff --git a/project/effectfields/colorfield.h b/project/effectfields/colorfield.h new file mode 100644 index 000000000..91b4b8a7a --- /dev/null +++ b/project/effectfields/colorfield.h @@ -0,0 +1,18 @@ +#ifndef COLORFIELD_H +#define COLORFIELD_H + +#include "effectfield.h" + +class ColorField : public EffectField +{ + Q_OBJECT +public: + ColorField(EffectRow* parent, const QString& id); + + QColor GetColorAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // COLORFIELD_H diff --git a/project/effectfields/combofield.cpp b/project/effectfields/combofield.cpp new file mode 100644 index 000000000..342dd6a21 --- /dev/null +++ b/project/effectfields/combofield.cpp @@ -0,0 +1,25 @@ +#include "combofield.h" + +ComboField::ComboField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_COMBO) +{} + +void ComboField::AddItem(const QString &text, const QVariant &data) +{ + ComboFieldItem item; + + item.name = text; + item.data.append(data); + + items_.append(item); +} + +QVariant ComboField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString ComboField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/combofield.h b/project/effectfields/combofield.h new file mode 100644 index 000000000..00c229259 --- /dev/null +++ b/project/effectfields/combofield.h @@ -0,0 +1,29 @@ +#ifndef COMBOFIELD_H +#define COMBOFIELD_H + +#include "effectfield.h" + +struct ComboFieldItem { + QString name; + QVector data; +}; + +class ComboField : public EffectField +{ + Q_OBJECT +public: + ComboField(EffectRow* parent, const QString& id); + + void AddItem(const QString& text, const QVariant& data); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); + +signals: + void IndexChanged(int i); + +private: + QVector items_; +}; + +#endif // COMBOFIELD_H diff --git a/project/effectfields/doublefield.cpp b/project/effectfields/doublefield.cpp new file mode 100644 index 000000000..783f65ed0 --- /dev/null +++ b/project/effectfields/doublefield.cpp @@ -0,0 +1,60 @@ +#include "doublefield.h" + +DoubleField::DoubleField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_DOUBLE), + min_(DBL_MIN), + max_(DBL_MAX), + value_set_(false) +{ + connect(this, SIGNAL(Changed()), this, SLOT(ValueHasBeenSet()), Qt::DirectConnection); +} + +double DoubleField::GetDoubleAt(double timecode) +{ + return GetValueAt(timecode).toDouble(); +} + +void DoubleField::SetMinimum(double minimum) +{ + min_ = minimum; +} + +void DoubleField::SetMaximum(double maximum) +{ + max_ = maximum; +} + +void DoubleField::SetDefault(double d) +{ + default_ = d; + + if (!value_set_) { + SetValueAt(0, d); + value_set_ = false; + } +} + +void DoubleField::SetDisplayType(LabelSlider::DisplayType type) +{ + display_type_ = type; +} + +void DoubleField::SetFrameRate(const double &rate) +{ + frame_rate_ = rate; +} + +QVariant DoubleField::ConvertStringToValue(const QString &s) +{ + return s.toDouble(); +} + +QString DoubleField::ConvertValueToString(const QVariant &v) +{ + return QString::number(v.toDouble()); +} + +void DoubleField::ValueHasBeenSet() +{ + value_set_ = true; +} diff --git a/project/effectfields/doublefield.h b/project/effectfields/doublefield.h new file mode 100644 index 000000000..c5deb0c21 --- /dev/null +++ b/project/effectfields/doublefield.h @@ -0,0 +1,50 @@ +#ifndef DOUBLEFIELD_H +#define DOUBLEFIELD_H + +#include "effectfield.h" +#include "ui/labelslider.h" + +class DoubleField : public EffectField +{ + Q_OBJECT +public: + DoubleField(EffectRow* parent, const QString& id); + + /** + * @brief Get double value at timecode + * + * Convenience function. Equivalent to GetValueAt().toDouble() + * + * @param timecode + * + * Timecode to retrieve value at + * + * @return + * + * Double value at the set timecode + */ + double GetDoubleAt(double timecode); + + void SetMinimum(double minimum); + void SetMaximum(double maximum); + void SetDefault(double maximum); + + void SetDisplayType(LabelSlider::DisplayType type); + void SetFrameRate(const double& rate); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +private: + double min_; + double max_; + double default_; + + LabelSlider::DisplayType display_type_; + double frame_rate_; + + bool value_set_; +private slots: + void ValueHasBeenSet(); +}; + +#endif // DOUBLEFIELD_H diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp new file mode 100644 index 000000000..96d32366b --- /dev/null +++ b/project/effectfields/effectfield.cpp @@ -0,0 +1,368 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "effectfield.h" + +#include "ui/labelslider.h" +#include "ui/colorbutton.h" +#include "ui/texteditex.h" +#include "ui/checkboxex.h" +#include "ui/comboboxex.h" +#include "ui/fontcombobox.h" +#include "ui/embeddedfilechooser.h" + +#include "io/config.h" + +#include "project/effectrow.h" +#include "project/effect.h" + +#include "project/undo.h" +#include "project/clip.h" +#include "project/sequence.h" + +#include "io/math.h" + +#include +#include + +#include "debug.h" + +EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) : + QObject(parent), + type_(t), + id_(i), + enabled_(true) +{ + // EffectField MUST be created with a parent. + Q_ASSERT(parent != nullptr); + Q_ASSERT(!i.isEmpty()); + + parent->AddField(this); + /* + switch (t) { + case EFFECT_FIELD_DOUBLE: + { + LabelSlider* ls = new LabelSlider(); + ui_element = ls; + connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change())); + connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked())); + } + break; + case EFFECT_FIELD_COLOR: + { + ColorButton* cb = new ColorButton(); + ui_element = cb; + connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_STRING: + { + TextEditEx* edit = new TextEditEx(); + + // TODO magic number 2 - It seems to just be +1 for the top and +1 for the bottom, which is sort of sensible but + // feels a little tacky? + edit->setFixedHeight(qCeil(edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + + edit->document()->documentMargin() + + edit->document()->documentMargin() + + 2)); + + edit->setUndoRedoEnabled(true); + ui_element = edit; + connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_BOOL: + { + CheckboxEx* cb = new CheckboxEx(); + ui_element = cb; + connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change())); + connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); + } + break; + case EFFECT_FIELD_COMBO: + { + ComboBoxEx* cb = new ComboBoxEx(); + ui_element = cb; + connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_FONT: + { + FontCombobox* fcb = new FontCombobox(); + ui_element = fcb; + connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); + } + break; + case EFFECT_FIELD_FILE: + { + EmbeddedFileChooser* efc = new EmbeddedFileChooser(); + ui_element = efc; + connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change())); + } + break; + } + */ + + // Set a very base default value + SetValueAt(0, 0); +} + +EffectField::~EffectField() {} + +EffectRow *EffectField::GetParentRow() +{ + return static_cast(parent()); +} + +int EffectField::GetColumnSpan() +{ + return colspan_; +} + +void EffectField::SetColumnSpan(int i) +{ + colspan_ = i; +} + +QVariant EffectField::GetValueAt(double timecode) +{ + Q_ASSERT(!keyframes.isEmpty()); + + if (HasKeyframes()) { + int before_keyframe; + int after_keyframe; + double progress; + get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); + + const QVariant& before_data = keyframes.at(before_keyframe).data; + switch (type_) { + case EFFECT_FIELD_DOUBLE: + { + double value; + 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); + + double before_dbl = before_key.data.toDouble(); + double after_dbl = after_key.data.toDouble(); + + if (before_key.type == EFFECT_KEYFRAME_HOLD) { + // hold + value = before_dbl; + } else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) { + // bezier interpolation + if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { + // cubic bezier + double t = cubic_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), 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); + } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier + // last keyframe is the bezier one + double t = quad_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time); + value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t); + } else { + // this keyframe is the bezier one + double t = quad_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); + value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t); + } + } else { + // linear + value = double_lerp(before_dbl, after_dbl, progress); + } + } + return value; + } + case EFFECT_FIELD_COLOR: + { + QColor value; + if (before_keyframe == after_keyframe) { + value = keyframes.at(before_keyframe).data.value(); + } else { + QColor before_data = keyframes.at(before_keyframe).data.value(); + QColor after_data = keyframes.at(after_keyframe).data.value(); + 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)); + } + return value; + } + case EFFECT_FIELD_STRING: + case EFFECT_FIELD_BOOL: + case EFFECT_FIELD_COMBO: + case EFFECT_FIELD_FONT: + case EFFECT_FIELD_FILE: + return before_data; + } + } + + return keyframes.first().data; +} + +void EffectField::SetValueAt(double timecode, const QVariant &value) +{ + if (keyframes.isEmpty()) { + EffectKeyframe key; + key.data = value; + keyframes.append(key); + return; + } + + if (GetParentRow()->isKeyframing()) { + // create keyframe here + } else { + keyframes.first().data = value; + } + + emit Changed(); +} + +const EffectField::EffectFieldType &EffectField::type() +{ + return type_; +} + +const QString &EffectField::id() +{ + return id_; +} + +double EffectField::GetValidKeyframeHandlePosition(int key, bool post) { + int comp_key = -1; + + // find keyframe before or after this one + for (int i=0;i keyframes.at(key).time) == post) + && (comp_key == -1 + || ((keyframes.at(i).time < keyframes.at(comp_key).time) == post))) { + // compare with next keyframe for post or previous frame for pre + comp_key = i; + } + } + + double adjusted_key = post ? keyframes.at(key).post_handle_x : keyframes.at(key).pre_handle_x; + + // if this is the earliest/latest keyframe, no validation is required + if (comp_key == -1) { + return adjusted_key; + } + + double comp = keyframes.at(comp_key).time - keyframes.at(key).time; + + // if comp keyframe is bezier, validate with its accompanying handle + if (keyframes.at(comp_key).type == EFFECT_KEYFRAME_BEZIER) { + double relative_comp_handle = comp + (post ? keyframes.at(comp_key).pre_handle_x : keyframes.at(comp_key).post_handle_x); + // return an average + if ((post && keyframes.at(key).post_handle_x > relative_comp_handle) + || (!post && keyframes.at(key).pre_handle_x < relative_comp_handle)) { + adjusted_key = (adjusted_key + relative_comp_handle)*0.5; + } + } + + // don't let handle go beyond the compare keyframe's time + if (post == (adjusted_key > comp)) { + return comp; + } + + if (post == (adjusted_key < 0)) { + return 0; + } + + // original value is valid + return adjusted_key; +} + +double EffectField::frameToTimecode(long frame) { + return (double(frame) / GetParentRow()->parent_effect->parent_clip->sequence->frame_rate); +} + +long EffectField::timecodeToFrame(double timecode) { + return qRound(timecode * GetParentRow()->parent_effect->parent_clip->sequence->frame_rate); +} + +void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { + int before_keyframe_index = -1; + int after_keyframe_index = -1; + long before_keyframe_time = LONG_MIN; + long after_keyframe_time = LONG_MAX; + long frame = timecodeToFrame(timecode); + + for (int i=0;i before_keyframe_time) { + before_keyframe_index = i; + before_keyframe_time = eval_keyframe_time; + } else if (eval_keyframe_time > frame && eval_keyframe_time < after_keyframe_time) { + after_keyframe_index = i; + after_keyframe_time = eval_keyframe_time; + } + } + + if ((type_ == EFFECT_FIELD_DOUBLE || type_ == EFFECT_FIELD_COLOR) && (before_keyframe_index > -1 && after_keyframe_index > -1)) { + // interpolate + before = before_keyframe_index; + after = after_keyframe_index; + progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); + } else if (before_keyframe_index > -1) { + before = before_keyframe_index; + after = before_keyframe_index; + } else { + before = after_keyframe_index; + after = after_keyframe_index; + } +} + +bool EffectField::HasKeyframes() { + return (GetParentRow()->isKeyframing() && keyframes.size() > 1); +} + +void EffectField::ui_element_change() { + // TODO address this + //bool dragging_double = (type_ == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); + bool dragging_double = false; + ComboAction* ca = nullptr; + if (!dragging_double) ca = new ComboAction(); + //make_key_from_change(ca); + if (!dragging_double) olive::UndoStack.push(ca); + emit Changed(); +} + +/* +void EffectField::make_key_from_change(ComboAction* ca) { + if (GetParentRow()->isKeyframing()) { + GetParentRow()->set_keyframe_now(ca); + } else if (ca != nullptr) { + // set undo + ca->append(new EffectFieldUndo(this)); + } +} +*/ + +bool EffectField::IsEnabled() { + return enabled_; +} + +void EffectField::SetEnabled(bool e) { + enabled_ = e; + emit EnabledChanged(enabled_); +} diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h new file mode 100644 index 000000000..f5725e724 --- /dev/null +++ b/project/effectfields/effectfield.h @@ -0,0 +1,88 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef EFFECTFIELD_H +#define EFFECTFIELD_H + +#include +#include +#include + +#include "project/keyframe.h" + +class EffectRow; +class ComboAction; + +class EffectField : public QObject { + Q_OBJECT +public: + enum EffectFieldType { + EFFECT_FIELD_DOUBLE, + EFFECT_FIELD_COLOR, + EFFECT_FIELD_STRING, + EFFECT_FIELD_BOOL, + EFFECT_FIELD_COMBO, + EFFECT_FIELD_FONT, + EFFECT_FIELD_FILE + }; + + EffectField(EffectRow* parent, const QString& i, EffectFieldType t); + ~EffectField(); + + EffectRow* GetParentRow(); + + const EffectFieldType& type(); + const QString& id(); + + QVariant GetValueAt(double timecode); + void SetValueAt(double timecode, const QVariant& value); + + int GetColumnSpan(); + void SetColumnSpan(int i); + + virtual QVariant ConvertStringToValue(const QString& s) = 0; + virtual QString ConvertValueToString(const QVariant& v) = 0; + + double GetValidKeyframeHandlePosition(int key, bool post); + + bool IsEnabled(); + void SetEnabled(bool e); + QVector keyframes; + +public slots: + void ui_element_change(); +private: + EffectFieldType type_; + QString id_; + + bool HasKeyframes(); + double frameToTimecode(long frame); + long timecodeToFrame(double timecode); + void get_keyframe_data(double timecode, int& before, int& after, double& d); + + bool enabled_; + int colspan_; +signals: + void Changed(); + void Clicked(); + void EnabledChanged(bool); +}; + +#endif // EFFECTFIELD_H diff --git a/project/effectfields/filefield.cpp b/project/effectfields/filefield.cpp new file mode 100644 index 000000000..594cd6ff7 --- /dev/null +++ b/project/effectfields/filefield.cpp @@ -0,0 +1,22 @@ +#include "filefield.h" + +FileField::FileField(EffectRow* parent, const QString &id) : + EffectField(parent, id, EFFECT_FIELD_FILE) +{ + +} + +QString FileField::GetFileAt(double timecode) +{ + return GetValueAt(timecode).toString(); +} + +QVariant FileField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString FileField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/filefield.h b/project/effectfields/filefield.h new file mode 100644 index 000000000..edfcb280f --- /dev/null +++ b/project/effectfields/filefield.h @@ -0,0 +1,18 @@ +#ifndef FILEFIELD_H +#define FILEFIELD_H + +#include "effectfield.h" + +class FileField : public EffectField +{ + Q_OBJECT +public: + FileField(EffectRow* parent, const QString& id); + + QString GetFileAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // FILEFIELD_H diff --git a/project/effectfields/fontfield.cpp b/project/effectfields/fontfield.cpp new file mode 100644 index 000000000..faf88c55e --- /dev/null +++ b/project/effectfields/fontfield.cpp @@ -0,0 +1,22 @@ +#include "fontfield.h" + +FontField::FontField(EffectRow* parent, const QString &id) : + EffectField(parent, id, EFFECT_FIELD_FONT) +{ + +} + +QString FontField::GetFontAt(double timecode) +{ + return GetValueAt(timecode).toString(); +} + +QVariant FontField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString FontField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/fontfield.h b/project/effectfields/fontfield.h new file mode 100644 index 000000000..cf5b36c35 --- /dev/null +++ b/project/effectfields/fontfield.h @@ -0,0 +1,17 @@ +#ifndef FONTFIELD_H +#define FONTFIELD_H + +#include "effectfield.h" + +class FontField : public EffectField { + Q_OBJECT +public: + FontField(EffectRow* parent, const QString& id); + + QString GetFontAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // FONTFIELD_H diff --git a/project/effectfields/stringfield.cpp b/project/effectfields/stringfield.cpp new file mode 100644 index 000000000..77080607e --- /dev/null +++ b/project/effectfields/stringfield.cpp @@ -0,0 +1,22 @@ +#include "stringfield.h" + +StringField::StringField(EffectRow* parent, const QString& id) : + EffectField(parent, id, EFFECT_FIELD_STRING) +{ + +} + +QString StringField::GetStringAt(double timecode) +{ + return GetValueAt(timecode).toString(); +} + +QVariant StringField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString StringField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} diff --git a/project/effectfields/stringfield.h b/project/effectfields/stringfield.h new file mode 100644 index 000000000..36028d891 --- /dev/null +++ b/project/effectfields/stringfield.h @@ -0,0 +1,18 @@ +#ifndef STRINGFIELD_H +#define STRINGFIELD_H + +#include "effectfield.h" + +class StringField : public EffectField +{ + Q_OBJECT +public: + StringField(EffectRow* parent, const QString& id); + + QString GetStringAt(double timecode); + + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); +}; + +#endif // STRINGFIELD_H diff --git a/project/effectgizmo.cpp b/project/effectgizmo.cpp index 047903259..b506eaf61 100644 --- a/project/effectgizmo.cpp +++ b/project/effectgizmo.cpp @@ -21,46 +21,49 @@ #include "effectgizmo.h" #include "ui/labelslider.h" -#include "effectfield.h" +#include "effectfields/doublefield.h" EffectGizmo::EffectGizmo(int type) : - x_field1(nullptr), - x_field_multi1(1.0), - y_field1(nullptr), - y_field_multi1(1.0), - x_field2(nullptr), - x_field_multi2(1.0), - y_field2(nullptr), - y_field_multi2(1.0), - type(type), - cursor(-1) + x_field1(nullptr), + x_field_multi1(1.0), + y_field1(nullptr), + y_field_multi1(1.0), + x_field2(nullptr), + x_field_multi2(1.0), + y_field2(nullptr), + y_field_multi2(1.0), + type(type), + cursor(-1) { - int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1; - world_pos.resize(point_count); - screen_pos.resize(point_count); + int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1; + world_pos.resize(point_count); + screen_pos.resize(point_count); - color = Qt::white; + color = Qt::white; } void EffectGizmo::set_previous_value() { - if (x_field1 != nullptr) static_cast(x_field1->ui_element)->set_previous_value(); - if (y_field1 != nullptr) static_cast(y_field1->ui_element)->set_previous_value(); - if (x_field2 != nullptr) static_cast(x_field2->ui_element)->set_previous_value(); - if (y_field2 != nullptr) static_cast(y_field2->ui_element)->set_previous_value(); + // TODO address this + /* + if (x_field1 != nullptr) static_cast(x_field1->ui_element)->set_previous_value(); + if (y_field1 != nullptr) static_cast(y_field1->ui_element)->set_previous_value(); + if (x_field2 != nullptr) static_cast(x_field2->ui_element)->set_previous_value(); + if (y_field2 != nullptr) static_cast(y_field2->ui_element)->set_previous_value(); + */ } int EffectGizmo::get_point_count() { - return world_pos.size(); + return world_pos.size(); } int EffectGizmo::get_type() { - return type; + return type; } int EffectGizmo::get_cursor() { - return cursor; + return cursor; } void EffectGizmo::set_cursor(int c) { - cursor = c; + cursor = c; } diff --git a/project/effectgizmo.h b/project/effectgizmo.h index 2f2dfbdfb..98a50962f 100644 --- a/project/effectgizmo.h +++ b/project/effectgizmo.h @@ -22,9 +22,9 @@ #define EFFECTGIZMO_H enum GizmoType { - GIZMO_TYPE_DOT, - GIZMO_TYPE_POLY, - GIZMO_TYPE_TARGET + GIZMO_TYPE_DOT, + GIZMO_TYPE_POLY, + GIZMO_TYPE_TARGET }; #define GIZMO_DOT_SIZE 2.5 @@ -36,37 +36,37 @@ enum GizmoType { #include #include -class EffectField; +class DoubleField; class EffectGizmo { public: - EffectGizmo(int type); + EffectGizmo(int type); - QVector world_pos; - QVector screen_pos; + QVector world_pos; + QVector screen_pos; - EffectField* x_field1; - double x_field_multi1; - EffectField* y_field1; - double y_field_multi1; - EffectField* x_field2; - double x_field_multi2; - EffectField* y_field2; - double y_field_multi2; + DoubleField* x_field1; + double x_field_multi1; + DoubleField* y_field1; + double y_field_multi1; + DoubleField* x_field2; + double x_field_multi2; + DoubleField* y_field2; + double y_field_multi2; - void set_previous_value(); + void set_previous_value(); - QColor color; - int get_point_count(); + QColor color; + int get_point_count(); - int get_type(); + int get_type(); - int get_cursor(); - void set_cursor(int c); + int get_cursor(); + void set_cursor(int c); private: - int type; - int cursor; + int type; + int cursor; }; #endif // EFFECTGIZMO_H diff --git a/project/effectrow.cpp b/project/effectrow.cpp index 11ef3f23f..51a3a429b 100644 --- a/project/effectrow.cpp +++ b/project/effectrow.cpp @@ -37,278 +37,251 @@ #include "ui/clickablelabel.h" EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row, bool keyframable) : - parent_effect(parent), - savable(save), - keyframing(false), - ui(uilayout), - name(n), - ui_row(row), - just_made_unsafe_keyframe(false) + parent_effect(parent), + savable(save), + keyframing(false), + ui(uilayout), + name_(n), + ui_row(row), + just_made_unsafe_keyframe(false) { - label = new ClickableLabel(name + ":"); + label = new ClickableLabel(name_ + ":"); - ui->addWidget(label, row, 0); + ui->addWidget(label, row, 0); - column_count = 1; + column_count = 1; - keyframe_nav = nullptr; - if (parent_effect->meta != nullptr - && parent_effect->meta->type != EFFECT_TYPE_TRANSITION - && keyframable) { - connect(label, SIGNAL(clicked()), this, SLOT(focus_row())); + keyframe_nav = nullptr; + if (parent_effect->meta != nullptr + && parent_effect->meta->type != EFFECT_TYPE_TRANSITION + && keyframable) { + connect(label, SIGNAL(clicked()), this, SLOT(FocusRow())); - keyframe_nav = new KeyframeNavigator(); - 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); - } + keyframe_nav = new KeyframeNavigator(); + connect(keyframe_nav, SIGNAL(GoToPreviousKeyframe()), this, SLOT(GoToPreviousKeyframe())); + connect(keyframe_nav, SIGNAL(ToggleKeyframe()), this, SLOT(ToggleKeyframe())); + connect(keyframe_nav, SIGNAL(GoToNextKeyframe()), this, SLOT(GoToNextKeyframe())); + connect(keyframe_nav, SIGNAL(keyframe_enabled_changed(bool)), this, SLOT(SetKeyframingEnabled(bool))); + connect(keyframe_nav, SIGNAL(clicked()), this, SLOT(FocusRow())); + ui->addWidget(keyframe_nav, row, 6); + } } EffectRow::~EffectRow() { - for (int i=0;isetParent(this); + fields_.append(field); } bool EffectRow::isKeyframing() { - return keyframing; + return keyframing; } void EffectRow::setKeyframing(bool b) { - if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) { - keyframing = b; - if (keyframe_nav != nullptr) { - keyframe_nav->enable_keyframes(b); - } - } + if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) { + keyframing = b; + if (keyframe_nav != nullptr) { + keyframe_nav->enable_keyframes(b); + } + } } -void EffectRow::set_keyframe_enabled(bool enabled) { - if (enabled) { - ComboAction* ca = new ComboAction(); - ca->append(new SetKeyframing(this, true)); - set_keyframe_now(ca); - olive::UndoStack.push(ca); - } else { - if (QMessageBox::question(panel_effect_controls, - tr("Disable Keyframes"), - tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - // clear - ComboAction* ca = new ComboAction(); - for (int i=0;ikeyframes.size();j++) { - ca->append(new KeyframeDelete(f, 0)); - } - } - ca->append(new SetKeyframing(this, false)); - olive::UndoStack.push(ca); - panel_effect_controls->update_keyframes(); - } else { - setKeyframing(true); - } - } +void EffectRow::SetKeyframingEnabled(bool enabled) { + if (enabled) { + ComboAction* ca = new ComboAction(); + ca->append(new SetKeyframing(this, true)); + set_keyframe_now(ca); + olive::UndoStack.push(ca); + } else { + if (QMessageBox::question(panel_effect_controls, + tr("Disable Keyframes"), + tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { + // clear + ComboAction* ca = new ComboAction(); + for (int i=0;ikeyframes.size();j++) { + ca->append(new KeyframeDelete(f, 0)); + } + } + ca->append(new SetKeyframing(this, false)); + olive::UndoStack.push(ca); + panel_effect_controls->update_keyframes(); + } else { + setKeyframing(true); + } + } } -void EffectRow::goto_previous_key() { - long key = LONG_MIN; +void EffectRow::GoToPreviousKeyframe() { + long key = LONG_MIN; Clip* c = parent_effect->parent_clip; - for (int i=0;ikeyframes.size();j++) { + for (int i=0;ikeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp < olive::ActiveSequence->playhead) { - key = qMax(comp, key); - } - } - } - if (key != LONG_MIN) panel_sequence_viewer->seek(key); + if (comp < olive::ActiveSequence->playhead) { + key = qMax(comp, key); + } + } + } + if (key != LONG_MIN) panel_sequence_viewer->seek(key); } -void EffectRow::toggle_key() { - QVector key_fields; - QVector key_field_index; +void EffectRow::ToggleKeyframe() { + QVector key_fields; + QVector key_field_index; Clip* c = parent_effect->parent_clip; - for (int j=0;jkeyframes.size();i++) { + for (int j=0;jkeyframes.size();i++) { long comp = c->timeline_in() - c->clip_in() + f->keyframes.at(i).time; - if (comp == olive::ActiveSequence->playhead) { - key_fields.append(f); - key_field_index.append(i); - } - } - } + if (comp == olive::ActiveSequence->playhead) { + key_fields.append(f); + key_field_index.append(i); + } + } + } - ComboAction* ca = new ComboAction(); - if (key_fields.size() == 0) { - // keyframe doesn't exist, set one - set_keyframe_now(ca); - } else { - for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); - } - } - olive::UndoStack.push(ca); - update_ui(false); + ComboAction* ca = new ComboAction(); + if (key_fields.size() == 0) { + // keyframe doesn't exist, set one + set_keyframe_now(ca); + } else { + for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); + } + } + olive::UndoStack.push(ca); + update_ui(false); } -void EffectRow::goto_next_key() { - long key = LONG_MAX; +void EffectRow::GoToNextKeyframe() { + long key = LONG_MAX; Clip* c = parent_effect->parent_clip; - for (int i=0;ikeyframes.size();j++) { + for (int i=0;ikeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp > olive::ActiveSequence->playhead) { - key = qMin(comp, key); - } - } - } - if (key != LONG_MAX) panel_sequence_viewer->seek(key); + if (comp > olive::ActiveSequence->playhead) { + key = qMin(comp, key); + } + } + } + if (key != LONG_MAX) panel_sequence_viewer->seek(key); } -void EffectRow::focus_row() { - panel_graph_editor->set_row(this); +void EffectRow::FocusRow() { + panel_graph_editor->set_row(this); } +/* EffectField* EffectRow::add_field(int type, const QString& id, int colspan) { - EffectField* field = new EffectField(this, type, id); - if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row())); - fields.append(field); - QWidget* element = field->get_ui_element(); - ui->addWidget(element, ui_row, column_count, 1, colspan); - column_count++; - connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed())); - return field; + EffectField* field = new EffectField(this, type, id); + if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row())); + fields_.append(field); + QWidget* element = field->get_ui_element(); + ui->addWidget(element, ui_row, column_count, 1, colspan); + column_count++; + connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed())); + return field; } +*/ void EffectRow::add_widget(QWidget* w) { - widgets.append(w); - ui->addWidget(w, ui_row, column_count); - column_count++; + widgets.append(w); + ui->addWidget(w, ui_row, column_count); + column_count++; } void EffectRow::set_keyframe_now(ComboAction* ca) { + // TODO address this... + /* long time = olive::ActiveSequence->playhead - parent_effect->parent_clip->timeline_in() + parent_effect->parent_clip->clip_in(); - if (!just_made_unsafe_keyframe) { - EffectKeyframe key; - key.time = time; + if (!just_made_unsafe_keyframe) { + EffectKeyframe key; + key.time = time; - unsafe_keys.resize(fieldCount()); - unsafe_old_data.resize(fieldCount()); - key_is_new.resize(fieldCount()); + unsafe_keys.resize(fieldCount()); + unsafe_old_data.resize(fieldCount()); + key_is_new.resize(fieldCount()); - for (int i=0;ikeyframes.size();j++) { - if (f->keyframes.at(j).time == time) { - exist_key = j; - } else if (f->keyframes.at(j).time < time - && f->keyframes.at(closest_key).time < f->keyframes.at(j).time) { - closest_key = j; - } - } - if (exist_key == -1) { - key.type = (f->keyframes.size() == 0) ? EFFECT_KEYFRAME_LINEAR : f->keyframes.at(closest_key).type; - key.data = f->get_current_data();//f->keyframes.at(closest_key).data; - unsafe_keys[i] = f->keyframes.size(); - f->keyframes.append(key); - key_is_new[i] = true; - } else { - unsafe_keys[i] = exist_key; - key_is_new[i] = false; - } - unsafe_old_data[i] = f->get_current_data(); - } - just_made_unsafe_keyframe = true; - } + int exist_key = -1; + int closest_key = 0; + for (int j=0;jkeyframes.size();j++) { + if (f->keyframes.at(j).time == time) { + exist_key = j; + } else if (f->keyframes.at(j).time < time + && f->keyframes.at(closest_key).time < f->keyframes.at(j).time) { + closest_key = j; + } + } + if (exist_key == -1) { + key.type = (f->keyframes.size() == 0) ? EFFECT_KEYFRAME_LINEAR : f->keyframes.at(closest_key).type; + key.data = f->GetCurrentValue(); + unsafe_keys[i] = f->keyframes.size(); + f->keyframes.append(key); + key_is_new[i] = true; + } else { + unsafe_keys[i] = exist_key; + key_is_new[i] = false; + } + unsafe_old_data[i] = f->GetCurrentValue(); + } + just_made_unsafe_keyframe = true; + } - for (int i=0;ikeyframes[unsafe_keys.at(i)].data = field(i)->get_current_data(); - } + for (int i=0;ikeyframes[unsafe_keys.at(i)].data = field(i)->GetCurrentValue(); + } - if (ca != nullptr) { - for (int i=0;iappend(new KeyframeFieldSet(field(i), unsafe_keys.at(i))); - ca->append(new SetQVariant(&field(i)->keyframes[unsafe_keys.at(i)].data, unsafe_old_data.at(i), field(i)->get_current_data())); - } - unsafe_keys.clear(); - unsafe_old_data.clear(); - just_made_unsafe_keyframe = false; - } + if (ca != nullptr) { + for (int i=0;iappend(new KeyframeFieldSet(field(i), unsafe_keys.at(i))); + ca->append(new SetQVariant(&field(i)->keyframes[unsafe_keys.at(i)].data, unsafe_old_data.at(i), field(i)->GetCurrentValue())); + } + unsafe_keys.clear(); + unsafe_old_data.clear(); + just_made_unsafe_keyframe = false; + } - panel_effect_controls->update_keyframes(); - - - - - - /*if (ca != nullptr) { - just_made_unsafe_keyframe = false; - } else { - if (!just_made_unsafe_keyframe) { - just_made_unsafe_keyframe = true; - } - }*/ - - - /*int index = -1; - long time = sequence->playhead-parent_effect->parent_clip->timeline_in+parent_effect->parent_clip->clip_in; - for (int j=0;jkeyframes.size();i++) { - if (f->keyframes.at(i).time == time) { - index = i; - break; - } - } - } - - KeyframeSet* ks = new KeyframeSet(this, index, time, just_made_unsafe_keyframe); - - if (ca != nullptr) { - just_made_unsafe_keyframe = false; - ca->append(ks); - } else { - if (index == -1) just_made_unsafe_keyframe = true; - ks->redo(); - delete ks; - } - - panel_effect_controls->update_keyframes();*/ + panel_effect_controls->update_keyframes(); + */ } void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) { - for (int j=0;jkeyframes.size();i++) { - if (f->keyframes.at(i).time == time) { - ca->append(new KeyframeDelete(f, i)); - break; - } - } - } + for (int j=0;jkeyframes.size();i++) { + if (f->keyframes.at(i).time == time) { + ca->append(new KeyframeDelete(f, i)); + break; + } + } + } } -const QString &EffectRow::get_name() { - return name; +const QString &EffectRow::name() { + return name_; } EffectField* EffectRow::field(int i) { - return fields.at(i); + return fields_.at(i); } int EffectRow::fieldCount() { - return fields.size(); + return fields_.size(); } diff --git a/project/effectrow.h b/project/effectrow.h index 845286d6e..9b61ac6c3 100644 --- a/project/effectrow.h +++ b/project/effectrow.h @@ -1,4 +1,4 @@ -/*** +/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team @@ -34,47 +34,51 @@ class QHBoxLayout; class KeyframeNavigator; class ClickableLabel; +#include "effectfields.h" + class EffectRow : public QObject { - Q_OBJECT + Q_OBJECT public: - EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row, bool keyframable = true); - ~EffectRow(); - EffectField* add_field(int type, const QString &id, int colspan = 1); - void add_widget(QWidget *w); - EffectField* field(int i); - int fieldCount(); - void set_keyframe_now(ComboAction *ca); - void delete_keyframe_at_time(ComboAction *ca, long time); - ClickableLabel* label; - Effect* parent_effect; - bool savable; - const QString& get_name(); + EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row, bool keyframable = true); + ~EffectRow(); - bool isKeyframing(); - void setKeyframing(bool); + void AddField(EffectField* field); + + void add_widget(QWidget *w); + EffectField* field(int i); + int fieldCount(); + void set_keyframe_now(ComboAction *ca); + void delete_keyframe_at_time(ComboAction *ca, long time); + ClickableLabel* label; + Effect* parent_effect; + bool savable; + const QString& name(); + + bool isKeyframing(); + void setKeyframing(bool); public slots: - void goto_previous_key(); - void toggle_key(); - void goto_next_key(); - void focus_row(); + void GoToPreviousKeyframe(); + void ToggleKeyframe(); + void GoToNextKeyframe(); + void FocusRow(); private slots: - void set_keyframe_enabled(bool); + void SetKeyframingEnabled(bool); private: - bool keyframing; - QGridLayout* ui; - QString name; - int ui_row; - QVector fields; - QVector widgets; + bool keyframing; + QGridLayout* ui; + QString name_; + int ui_row; + QVector fields_; + QVector widgets; - KeyframeNavigator* keyframe_nav; + KeyframeNavigator* keyframe_nav; - bool just_made_unsafe_keyframe; - QVector unsafe_keys; - QVector unsafe_old_data; - QVector key_is_new; + bool just_made_unsafe_keyframe; + QVector unsafe_keys; + QVector unsafe_old_data; + QVector key_is_new; - int column_count; + int column_count; }; #endif // EFFECTROW_H diff --git a/project/keyframe.cpp b/project/keyframe.cpp index 5811dc90c..64a36ce2d 100644 --- a/project/keyframe.cpp +++ b/project/keyframe.cpp @@ -22,45 +22,45 @@ #include -#include "effectfield.h" +#include "effectfields.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; + pre_handle_x = -40; + pre_handle_y = 0; + post_handle_x = 40; + post_handle_y = 0; } void delete_keyframes(QVector& selected_key_fields, QVector &selected_keys) { - QVector fields; - QVector key_indices; + QVector fields; + QVector key_indices; - for (int i=0;i 0) { - ComboAction* ca = new ComboAction(); - for (int i=0;iappend(new KeyframeDelete(fields.at(i), key_indices.at(i))); - } - olive::UndoStack.push(ca); - selected_keys.clear(); - selected_key_fields.clear(); - update_ui(false); - } + if (fields.size() > 0) { + ComboAction* ca = new ComboAction(); + for (int i=0;iappend(new KeyframeDelete(fields.at(i), key_indices.at(i))); + } + olive::UndoStack.push(ca); + selected_keys.clear(); + selected_key_fields.clear(); + update_ui(false); + } } diff --git a/project/transition.cpp b/project/transition.cpp index cb724f4fc..ecc53eb27 100644 --- a/project/transition.cpp +++ b/project/transition.cpp @@ -42,21 +42,21 @@ #include Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : - Effect(c, em), secondary_clip(s), - length(30) + Effect(c, em), + secondary_clip(s) { - length_field = add_row(tr("Length"), false)->add_field(EFFECT_FIELD_DOUBLE, "length"); + EffectRow* length_row = add_row(tr("Length"), false, false); + length_field = new DoubleField(length_row, "length"); + length_field->SetDefault(30); + length_field->SetMinimum(0); + length_field->SetDisplayType(LabelSlider::LABELSLIDER_FRAMENUMBER); + length_field->SetFrameRate(parent_clip->sequence == nullptr ? + parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider())); - length_field->set_double_default_value(30); - length_field->set_double_minimum_value(0); - - LabelSlider* length_ui_ele = static_cast(length_field->ui_element); - length_ui_ele->set_display_type(LABELSLIDER_FRAMENUMBER); - length_ui_ele->set_frame_rate(parent_clip->sequence == nullptr ? parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); } TransitionPtr Transition::copy(Clip *c, Clip *s) { - return Transition::Create(c, s, meta, length); + return Transition::Create(c, s, meta, get_true_length()); } void Transition::save(QXmlStreamWriter &stream) { @@ -64,20 +64,19 @@ void Transition::save(QXmlStreamWriter &stream) { Effect::save(stream); } -void Transition::set_length(long l) { - length = l; - length_field->set_double_value(l); +void Transition::set_length(int l) { + length_field->SetValueAt(0, l); } -long Transition::get_true_length() { - return length; +int Transition::get_true_length() { + return length_field->GetValueAt(0).toInt(); } -long Transition::get_length() { +int Transition::get_length() { if (secondary_clip != nullptr) { - return length * 2; + return get_true_length() * 2; } - return length; + return get_true_length(); } Clip* Transition::get_opened_clip() { @@ -99,7 +98,6 @@ Clip* Transition::get_closed_clip() { } void Transition::set_length_from_slider() { - set_length(length_field->get_double_value(0)); update_ui(false); } @@ -114,7 +112,7 @@ TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s, const EffectMeta* em) case TRANSITION_INTERNAL_LINEARFADE: return TransitionPtr(new LinearFadeTransition(c, s, em)); case TRANSITION_INTERNAL_EXPONENTIALFADE: return TransitionPtr(new ExponentialFadeTransition(c, s, em)); case TRANSITION_INTERNAL_LOGARITHMICFADE: return TransitionPtr(new LogarithmicFadeTransition(c, s, em)); - case TRANSITION_INTERNAL_CUBE: return TransitionPtr(new CubeTransition(c, s, em)); + //case TRANSITION_INTERNAL_CUBE: return TransitionPtr(new CubeTransition(c, s, em)); } } else { qCritical() << "Invalid transition data"; diff --git a/project/transition.h b/project/transition.h index a88f55bc9..ecce355a3 100644 --- a/project/transition.h +++ b/project/transition.h @@ -34,7 +34,7 @@ enum TransitionInternal { TRANSITION_INTERNAL_LINEARFADE, TRANSITION_INTERNAL_EXPONENTIALFADE, TRANSITION_INTERNAL_LOGARITHMICFADE, - TRANSITION_INTERNAL_CUBE, + //TRANSITION_INTERNAL_CUBE, TRANSITION_INTERNAL_COUNT }; @@ -50,9 +50,9 @@ public: virtual void save(QXmlStreamWriter& stream) override; - void set_length(long l); - long get_true_length(); - long get_length(); + void set_length(int l); + int get_true_length(); + int get_length(); Clip* get_opened_clip(); Clip* get_closed_clip(); @@ -62,8 +62,7 @@ public: private slots: void set_length_from_slider(); private: - long length; // used only for transitions - EffectField* length_field; + DoubleField* length_field; }; #endif // TRANSITION_H diff --git a/project/undo.cpp b/project/undo.cpp index 3d30b5e69..fca7f6ff6 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -666,25 +666,21 @@ void KeyframeDelete::doRedo() { field->keyframes.removeAt(index); } -EffectFieldUndo::EffectFieldUndo(EffectField* f) { - field = f; - done = true; - - old_val = field->get_previous_data(); - new_val = field->get_current_data(); -} +/* +EffectFieldUndo::EffectFieldUndo(EffectField* f, const QVariant& old_data, const QVariant new_data) : + field(f), + old_val(old_data), + new_val(new_data) +{} void EffectFieldUndo::doUndo() { - field->set_current_data(old_val); - done = false; - + field->SetCurrentValue(old_val); } void EffectFieldUndo::doRedo() { - if (!done) { - field->set_current_data(new_val); - } + field->SetCurrentValue(new_val); } +*/ SetClipProperty::SetClipProperty(SetClipPropertyType type) : type_(type) {} diff --git a/project/undo.h b/project/undo.h index c63bc9e98..273149794 100644 --- a/project/undo.h +++ b/project/undo.h @@ -23,7 +23,7 @@ #include "project/projectelements.h" #include "project/selection.h" -#include "project/effectfield.h" +#include "project/effectfields/effectfield.h" #include "ui/labelslider.h" #include "ui/sourcetable.h" @@ -352,7 +352,7 @@ private: class EffectFieldUndo : public OliveAction { public: - EffectFieldUndo(EffectField* field); + EffectFieldUndo(EffectField* field, const QVariant &old_data, const QVariant new_data); virtual void doUndo() override; virtual void doRedo() override; private: diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 4f6a08990..68d91073c 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -115,11 +115,11 @@ void process_effect(Clip* c, bool& texture_failed, int data) { if (e->is_enabled()) { - if (e->enable_coords) { + if (e->Flags() & Effect::CoordsFlag) { e->process_coords(timecode, coords, data); } - bool can_process_shaders = (e->enable_shader && olive::CurrentRuntimeConfig.shaders_are_enabled); - if (can_process_shaders || e->enable_superimpose) { + bool can_process_shaders = ((e->Flags() & Effect::ShaderFlag) && olive::CurrentRuntimeConfig.shaders_are_enabled); + if (can_process_shaders || (e->Flags() & Effect::SuperimposeFlag)) { e->startEffect(); if (can_process_shaders && e->is_glsl_linked()) { for (int i=0;igetIterations();i++) { @@ -128,7 +128,7 @@ void process_effect(Clip* c, fbo_switcher = !fbo_switcher; } } - if (e->enable_superimpose) { + if (e->Flags() & Effect::SuperimposeFlag) { GLuint superimpose_texture = e->process_superimpose(timecode); if (superimpose_texture == 0) { @@ -399,7 +399,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0.0; coords.textureBottomLeftY = coords.textureBottomRightY = coords.textureTopRightX = coords.textureBottomRightX = 1.0; coords.textureTopLeftQ = coords.textureTopRightQ = coords.textureTopLeftQ = coords.textureBottomLeftQ = 1; - coords.blendmode = BLEND_MODE_NORMAL; + coords.blendmode = -1; coords.opacity = 1.0; // if auto-scale is enabled, auto-scale the clip @@ -615,6 +615,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } } + /* // visually update all the keyframe values if (c->sequence == params.seq) { // only if you can currently see them double ts = (playhead - c->timeline_in(true) + c->clip_in(true))/s->frame_rate; @@ -628,6 +629,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { } } } + */ } } else { params.texture_failed = true; diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 86ae1aba9..3f51dda3f 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -245,7 +245,7 @@ void GraphView::paintEvent(QPaintEvent *) { for (int i=row->fieldCount()-1;i>=0;i--) { EffectField* field = row->field(i); - if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { // sort keyframes by time QVector sorted_keys = sort_keys_from_field(field); @@ -266,8 +266,8 @@ void GraphView::paintEvent(QPaintEvent *) { } else { const EffectKeyframe& last_key = field->keyframes.at(sorted_keys.at(j-1)); - double pre_handle = field->get_validated_keyframe_handle(sorted_keys.at(j), false); - double last_post_handle = field->get_validated_keyframe_handle(sorted_keys.at(j-1), true); + double pre_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j), false); + double last_post_handle = field->GetValidKeyframeHandlePosition(sorted_keys.at(j-1), true); if (last_key.type == EFFECT_KEYFRAME_HOLD) { // hold @@ -387,7 +387,7 @@ void GraphView::mousePressEvent(QMouseEvent *event) { } else { for (int i=0;ifieldCount();i++) { EffectField* field = row->field(i); - if (field->type == EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { + if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { for (int j=0;jkeyframes.size();j++) { const EffectKeyframe& key = field->keyframes.at(j); int key_x = get_screen_x(key.time); @@ -833,7 +833,7 @@ void GraphView::set_row(EffectRow *r) { if (row != nullptr) { field_visibility.resize(row->fieldCount()); for (int i=0;ifieldCount();i++) { - field_visibility[i] = row->field(i)->is_enabled(); + field_visibility[i] = row->field(i)->IsEnabled(); } visible_in = row->parent_effect->parent_clip->timeline_in(); set_view_to_all(); diff --git a/ui/graphview.h b/ui/graphview.h index 203e80202..bc1e96473 100644 --- a/ui/graphview.h +++ b/ui/graphview.h @@ -25,7 +25,7 @@ #include #include "project/effectrow.h" -#include "project/effectfield.h" +#include "project/effectfields.h" QColor get_curve_color(int index, int length); diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index fcca08c26..4c00dd862 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -250,7 +250,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { if (mouse_y > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && mouse_y < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) { EffectRow* row = rows.at(i); - row->focus_row(); + row->FocusRow(); for (int k=0;kfieldCount();k++) { EffectField* f = row->field(k); @@ -376,7 +376,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { if (panel_timeline->snapping) { for (int i=0;iparent_row->parent_effect->parent_clip; + Clip* c = field->GetParentRow()->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(olive::ActiveSequence->playhead, &key_eval)) { diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 9791def51..9319d4528 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -56,7 +56,7 @@ void LabelSlider::set_frame_rate(double d) { frame_rate = d; } -void LabelSlider::set_display_type(int type) { +void LabelSlider::set_display_type(const DisplayType& type) { display_type = type; setText(valueToString()); } @@ -112,8 +112,9 @@ QString LabelSlider::valueToString() { return db_str; } + default: + return QString::number(v, 'f', decimal_places); } - return QString::number(v, 'f', decimal_places); } } diff --git a/ui/labelslider.h b/ui/labelslider.h index ae0eae0c0..5c203eaa6 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -24,13 +24,6 @@ #include #include -enum LabelSliderDisplayType { - LABELSLIDER_NORMAL, - LABELSLIDER_FRAMENUMBER, - LABELSLIDER_PERCENT, - LABELSLIDER_DECIBEL -}; - /** * @brief The LabelSlider class * @@ -53,6 +46,13 @@ public: */ void set_frame_rate(double d); + enum DisplayType { + LABELSLIDER_NORMAL, + LABELSLIDER_FRAMENUMBER, + LABELSLIDER_PERCENT, + LABELSLIDER_DECIBEL + }; + /** * @brief Sets the way to display the value * @@ -65,9 +65,9 @@ public: * * @param type * - * The display type to set to. Should be a member of `enum LabelSliderDisplayType`. + * The display type to set to. */ - void set_display_type(int type); + void set_display_type(const DisplayType& type); /** * @brief Set the value @@ -205,7 +205,7 @@ private: bool set; - int display_type; + DisplayType display_type; double frame_rate; diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp index 7d6461ed4..f56bcf1cc 100644 --- a/ui/texteditex.cpp +++ b/ui/texteditex.cpp @@ -22,41 +22,71 @@ #include +/* TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) { - setUndoRedoEnabled(false); - connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals())); - connect(this, SIGNAL(updateSelf()), this, SLOT(updateText())); + setUndoRedoEnabled(false); + connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals())); + connect(this, SIGNAL(updateSelf()), this, SLOT(updateText())); } const QString& TextEditEx::getPlainTextEx() { - return text; + return text; } void TextEditEx::setPlainTextEx(const QString &t) { - previousText = text; - text = t; - emit updateSelf(); + previousText = text; + text = t; + emit updateSelf(); } const QString &TextEditEx::getPreviousValue() { - return previousText; + return previousText; } void TextEditEx::updateInternals() { - previousText = text; - text = toPlainText(); + previousText = text; + text = toPlainText(); } void TextEditEx::updateText() { - blockSignals(true); + blockSignals(true); - int pos = textCursor().position(); + int pos = textCursor().position(); - setPlainText(text); + setPlainText(text); - QTextCursor newCursor(document()); - newCursor.setPosition(pos); - setTextCursor(newCursor); + QTextCursor newCursor(document()); + newCursor.setPosition(pos); + setTextCursor(newCursor); - blockSignals(false); + blockSignals(false); +} +*/ + +#include + +#include "dialogs/texteditdialog.h" +#include "mainwindow.h" + +TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) +{ + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); +} + +void TextEditEx::text_edit_menu() { + QMenu menu; + + menu.addAction(tr("&Edit Text"), this, SLOT(open_text_edit())); + + menu.exec(QCursor::pos()); +} + +void TextEditEx::open_text_edit() { + TextEditDialog ted(olive::MainWindow, this->toHtml()); + ted.exec(); + QString result = ted.get_string(); + if (!result.isEmpty()) { + setHtml(result); + } } diff --git a/ui/texteditex.h b/ui/texteditex.h index b345859a6..aca586034 100644 --- a/ui/texteditex.h +++ b/ui/texteditex.h @@ -23,21 +23,31 @@ #include +/* class TextEditEx : public QTextEdit { - Q_OBJECT + Q_OBJECT public: - TextEditEx(QWidget* parent = 0); - void setPlainTextEx(const QString &text); - const QString& getPreviousValue(); - const QString& getPlainTextEx(); + TextEditEx(QWidget* parent = 0); + void setPlainTextEx(const QString &text); + const QString& getPreviousValue(); + const QString& getPlainTextEx(); signals: - void updateSelf(); + void updateSelf(); private slots: - void updateInternals(); - void updateText(); + void updateInternals(); + void updateText(); private: - QString previousText; - QString text; + QString previousText; + QString text; +}; +*/ + +class TextEditEx : public QTextEdit { +public: + TextEditEx(QWidget* parent); +private slots: + void text_edit_menu(); + void open_text_edit(); }; #endif // TEXTEDITEX_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 832412fec..828f2d5e1 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -1040,7 +1040,11 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { { c->set_name(tr("Bars")); EffectPtr e = Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_SOLID, EFFECT_TYPE_EFFECT)); - e->row(0)->field(0)->set_combo_index(1); + + // Auto-select bars + SolidEffect* solid_effect = static_cast(e.get()); + solid_effect->SetType(SolidEffect::SOLID_TYPE_BARS); + c->effects.append(e); } break; diff --git a/ui/updatenotification.cpp b/ui/updatenotification.cpp index 38d2a8f2d..aca2f47b7 100644 --- a/ui/updatenotification.cpp +++ b/ui/updatenotification.cpp @@ -14,7 +14,7 @@ UpdateNotification::UpdateNotification() void UpdateNotification::check() { -#if defined(_WIN32) || defined(__APPLE__) +#if defined(GITHASH) && (defined(_WIN32) || defined(__APPLE__)) QNetworkAccessManager* manager = new QNetworkAccessManager(); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(finished_slot(QNetworkReply *))); From 0b090ddc217f933614c826e6f8273175ee299add Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 12 Mar 2019 20:12:12 +1100 Subject: [PATCH 02/56] decoupled ui from effect row --- effects/internal/audionoiseeffect.cpp | 4 +- effects/internal/cornerpineffect.cpp | 10 +- effects/internal/fillleftrighteffect.cpp | 2 +- effects/internal/frei0reffect.cpp | 14 +-- effects/internal/paneffect.cpp | 2 +- effects/internal/shakeeffect.cpp | 6 +- effects/internal/solideffect.cpp | 8 +- effects/internal/texteffect.cpp | 32 +++--- effects/internal/timecodeeffect.cpp | 14 +-- effects/internal/toneeffect.cpp | 8 +- effects/internal/transformeffect.cpp | 14 +-- effects/internal/voideffect.cpp | 60 +++++------ effects/internal/volumeeffect.cpp | 2 +- effects/internal/vsthost.cpp | 17 ++-- effects/internal/vsthost.h | 4 +- olive.pro | 8 +- panels/grapheditor.cpp | 20 ++-- project/clip.cpp | 4 +- project/effect.cpp | 113 ++++++++++----------- project/effect.h | 1 - project/effectfields.h | 2 + project/effectfields/boolfield.h | 4 +- project/effectfields/buttonfield.cpp | 18 ++++ project/effectfields/buttonfield.h | 21 ++++ project/effectfields/colorfield.h | 4 +- project/effectfields/combofield.cpp | 10 -- project/effectfields/combofield.h | 3 - project/effectfields/effectfield.cpp | 26 +++-- project/effectfields/effectfield.h | 7 +- project/effectfields/filefield.cpp | 10 -- project/effectfields/filefield.h | 3 - project/effectfields/fontfield.cpp | 10 -- project/effectfields/fontfield.h | 3 - project/effectfields/labelfield.cpp | 7 ++ project/effectfields/labelfield.h | 13 +++ project/effectfields/stringfield.cpp | 10 -- project/effectfields/stringfield.h | 3 - project/effectrow.cpp | 124 ++++++++--------------- project/effectrow.h | 42 ++++---- project/transition.cpp | 2 +- project/undo.cpp | 10 +- project/undo.h | 4 +- ui/graphview.cpp | 74 +++++++------- ui/keyframedrawing.cpp | 48 ++++----- ui/keyframeview.cpp | 47 +++++---- 45 files changed, 416 insertions(+), 432 deletions(-) create mode 100644 project/effectfields/buttonfield.cpp create mode 100644 project/effectfields/buttonfield.h create mode 100644 project/effectfields/labelfield.cpp create mode 100644 project/effectfields/labelfield.h diff --git a/effects/internal/audionoiseeffect.cpp b/effects/internal/audionoiseeffect.cpp index 56b98ca3a..3f51bcf21 100644 --- a/effects/internal/audionoiseeffect.cpp +++ b/effects/internal/audionoiseeffect.cpp @@ -21,13 +21,13 @@ #include AudioNoiseEffect::AudioNoiseEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* amount_row = add_row(tr("Amount")); + EffectRow* amount_row = new EffectRow(this, tr("Amount")); amount_val = new DoubleField(amount_row, "amount"); amount_val->SetMinimum(0); amount_val->SetDefault(20); amount_val->SetMaximum(100); - EffectRow* mix_row = add_row(tr("Mix")); + EffectRow* mix_row = new EffectRow(this, tr("Mix")); mix_val = new BoolField(mix_row, "mix"); mix_val->SetValueAt(0, true); } diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index 315ed3f50..566247109 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -27,23 +27,23 @@ CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { SetFlags(Effect::CoordsFlag & Effect::ShaderFlag); - EffectRow* top_left = add_row(tr("Top Left")); + EffectRow* top_left = new EffectRow(this, tr("Top Left")); top_left_x = new DoubleField(top_left, "topleftx"); top_left_y = new DoubleField(top_left, "toplefty"); - EffectRow* top_right = add_row(tr("Top Right")); + EffectRow* top_right = new EffectRow(this, tr("Top Right")); top_right_x = new DoubleField(top_right, "toprightx"); top_right_y = new DoubleField(top_right, "toprighty"); - EffectRow* bottom_left = add_row(tr("Bottom Left")); + EffectRow* bottom_left = new EffectRow(this, tr("Bottom Left")); bottom_left_x = new DoubleField(bottom_left, "bottomleftx"); bottom_left_y = new DoubleField(bottom_left, "bottomlefty"); - EffectRow* bottom_right = add_row(tr("Bottom Right")); + EffectRow* bottom_right = new EffectRow(this, tr("Bottom Right")); bottom_right_x = new DoubleField(bottom_right, "bottomrightx"); bottom_right_y = new DoubleField(bottom_right, "bottomrighty"); - EffectRow* perspective_row = add_row(tr("Perspective")); + EffectRow* perspective_row = new EffectRow(this, tr("Perspective")); perspective = new BoolField(perspective_row, "perspective"); perspective->SetValueAt(0, true); diff --git a/effects/internal/fillleftrighteffect.cpp b/effects/internal/fillleftrighteffect.cpp index d23efa04f..ff0ebb68d 100644 --- a/effects/internal/fillleftrighteffect.cpp +++ b/effects/internal/fillleftrighteffect.cpp @@ -24,7 +24,7 @@ #define FILL_TYPE_RIGHT 1 FillLeftRightEffect::FillLeftRightEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* type_row = add_row(tr("Type")); + EffectRow* type_row = new EffectRow(this, tr("Type")); fill_type = new ComboField(type_row, "type"); fill_type->AddItem(tr("Fill Left with Right"), FILL_TYPE_LEFT); fill_type->AddItem(tr("Fill Right with Left"), FILL_TYPE_RIGHT); diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp index ea0b86f75..da45e4564 100644 --- a/effects/internal/frei0reffect.cpp +++ b/effects/internal/frei0reffect.cpp @@ -92,7 +92,7 @@ Frei0rEffect::Frei0rEffect(Clip* c, const EffectMeta *em) : get_param_info(¶m_info, i); if (param_info.type >= 0 && param_info.type <= F0R_PARAM_STRING) { - EffectRow* row = add_row(param_info.name); + EffectRow* row = new EffectRow(this, param_info.name); switch (param_info.type) { case F0R_PARAM_BOOL: new BoolField(row, QString::number(i)); @@ -147,19 +147,19 @@ void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *outpu switch (param_info.type) { case F0R_PARAM_BOOL: { - double b = param_row->field(0)->GetValueAt(timecode).toBool(); + double b = param_row->Field(0)->GetValueAt(timecode).toBool(); set_param(instance, &b, i); } break; case F0R_PARAM_DOUBLE: { - double d = param_row->field(0)->GetValueAt(timecode).toDouble()*0.01; + double d = param_row->Field(0)->GetValueAt(timecode).toDouble()*0.01; set_param(instance, &d, i); } break; case F0R_PARAM_COLOR: { - QColor qcolor = param_row->field(0)->GetValueAt(timecode).value(); + QColor qcolor = param_row->Field(0)->GetValueAt(timecode).value(); f0r_param_color fcolor; fcolor.r = float(qcolor.redF()); @@ -172,14 +172,14 @@ void Frei0rEffect::process_image(double timecode, uint8_t *input, uint8_t *outpu case F0R_PARAM_POSITION: { f0r_param_position pos; - pos.x = param_row->field(0)->GetValueAt(timecode).toDouble(); - pos.y = param_row->field(1)->GetValueAt(timecode).toDouble(); + pos.x = param_row->Field(0)->GetValueAt(timecode).toDouble(); + pos.y = param_row->Field(1)->GetValueAt(timecode).toDouble(); set_param(instance, &pos, i); } break; case F0R_PARAM_STRING: { - QByteArray bytes = param_row->field(0)->GetValueAt(timecode).toString().toUtf8(); + QByteArray bytes = param_row->Field(0)->GetValueAt(timecode).toString().toUtf8(); char* byte_data = bytes.data(); set_param(instance, &byte_data, i); } diff --git a/effects/internal/paneffect.cpp b/effects/internal/paneffect.cpp index 7ebb3af8e..987d6528f 100644 --- a/effects/internal/paneffect.cpp +++ b/effects/internal/paneffect.cpp @@ -29,7 +29,7 @@ #include "ui/collapsiblewidget.h" PanEffect::PanEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* pan_row = add_row(tr("Pan")); + EffectRow* pan_row = new EffectRow(this, tr("Pan")); pan_val = new DoubleField(pan_row, "pan"); pan_val->SetMinimum(-100); pan_val->SetDefault(0); diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index e27cb912a..4c1ea170f 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -36,17 +36,17 @@ ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { SetFlags(Effect::CoordsFlag); - EffectRow* intensity_row = add_row(tr("Intensity")); + EffectRow* intensity_row = new EffectRow(this, tr("Intensity")); intensity_val = new DoubleField(intensity_row, "intensity"); intensity_val->SetMinimum(0); intensity_val->SetDefault(25); - EffectRow* rotation_row = add_row(tr("Rotation")); + EffectRow* rotation_row = new EffectRow(this, tr("Rotation")); rotation_val = new DoubleField(rotation_row, "rotation"); rotation_val->SetMinimum(0); rotation_val->SetDefault(10); - EffectRow* frequency_row = add_row(tr("Frequency")); + EffectRow* frequency_row = new EffectRow(this, tr("Frequency")); frequency_val = new DoubleField(frequency_row, "frequency"); frequency_val->SetMinimum(0); frequency_val->SetDefault(5); diff --git a/effects/internal/solideffect.cpp b/effects/internal/solideffect.cpp index 6ed11ee98..76e067f27 100644 --- a/effects/internal/solideffect.cpp +++ b/effects/internal/solideffect.cpp @@ -40,23 +40,23 @@ SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : SetFlags(Effect::SuperimposeFlag); // Field for solid type - EffectRow* type_row = add_row(tr("Type")); + EffectRow* type_row = new EffectRow(this, tr("Type")); solid_type = new ComboField(type_row, "type"); solid_type->AddItem(tr("Solid Color"), SOLID_TYPE_COLOR); solid_type->AddItem(tr("SMPTE Bars"), SOLID_TYPE_BARS); solid_type->AddItem(tr("Checkerboard"), SOLID_TYPE_CHECKERBOARD); - EffectRow* opacity_row = add_row(tr("Opacity")); + EffectRow* opacity_row = new EffectRow(this, tr("Opacity")); opacity_field = new DoubleField(opacity_row, "opacity"); opacity_field->SetMinimum(0); opacity_field->SetDefault(0); opacity_field->SetMaximum(100); - EffectRow* solid_color_row = add_row(tr("Color")); + EffectRow* solid_color_row = new EffectRow(this, tr("Color")); solid_color_field = new ColorField(solid_color_row, "color"); solid_color_field->SetValueAt(0, QColor(Qt::red)); - EffectRow* checkerboard_size = add_row(tr("Checkerboard Size")); + EffectRow* checkerboard_size = new EffectRow(this, tr("Checkerboard Size")); checkerboard_size_field = new DoubleField(checkerboard_size, "checker_size"); checkerboard_size_field->SetMinimum(1); checkerboard_size_field->SetDefault(10); diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index f3fecf396..ff0b13c02 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -47,24 +47,24 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : { SetFlags(Effect::SuperimposeFlag); - EffectRow* text_field = add_row(tr("Text")); + EffectRow* text_field = new EffectRow(this, tr("Text")); text_val = new StringField(text_field, "text"); text_val->SetColumnSpan(2); - EffectRow* font_row = add_row(tr("Font")); + EffectRow* font_row = new EffectRow(this, tr("Font")); set_font_combobox = new FontField(font_row, "font"); set_font_combobox->SetColumnSpan(2); - EffectRow* size_row = add_row(tr("Size")); + EffectRow* size_row = new EffectRow(this, tr("Size")); size_val = new DoubleField(size_row, "size"); size_val->SetMinimum(0); size_val->SetColumnSpan(2); - EffectRow* color_row = add_row(tr("Color")); + EffectRow* color_row = new EffectRow(this, tr("Color")); set_color_button = new ColorField(color_row, "color"); set_color_button->SetColumnSpan(2); - EffectRow* alignment_row = add_row(tr("Alignment")); + EffectRow* alignment_row = new EffectRow(this, tr("Alignment")); halign_field = new ComboField(alignment_row, "halign"); halign_field->AddItem(tr("Left"), Qt::AlignLeft); halign_field->AddItem(tr("Center"), Qt::AlignHCenter); @@ -76,46 +76,46 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : valign_field->AddItem(tr("Center"), Qt::AlignVCenter); valign_field->AddItem(tr("Bottom"), Qt::AlignBottom); - EffectRow* word_wrap_row = add_row(tr("Word Wrap")); + EffectRow* word_wrap_row = new EffectRow(this, tr("Word Wrap")); word_wrap_field = new BoolField(word_wrap_row, "wordwrap"); word_wrap_field->SetColumnSpan(2); - EffectRow* outline_row = add_row(tr("Outline")); + EffectRow* outline_row = new EffectRow(this, tr("Outline")); outline_bool = new BoolField(outline_row, "outline"); outline_bool->SetColumnSpan(2); - EffectRow* outline_color_row = add_row(tr("Outline Color")); + EffectRow* outline_color_row = new EffectRow(this, tr("Outline Color")); outline_color = new ColorField(outline_color_row, "outlinecolor"); outline_color->SetColumnSpan(2); - EffectRow* outline_width_row = add_row(tr("Outline Width")); + EffectRow* outline_width_row = new EffectRow(this, tr("Outline Width")); outline_width = new DoubleField(outline_width_row, "outlinewidth"); outline_width->SetColumnSpan(2); outline_width->SetMinimum(0); - EffectRow* shadow_row = add_row(tr("Shadow")); + EffectRow* shadow_row = new EffectRow(this, tr("Shadow")); shadow_bool = new BoolField(shadow_row, "shadow"); shadow_bool->SetColumnSpan(2); - EffectRow* shadow_color_row = add_row(tr("Shadow Color")); + EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color")); shadow_color = new ColorField(shadow_color_row, "shadowcolor"); shadow_color->SetColumnSpan(2); - EffectRow* shadow_angle_row = add_row(tr("Shadow Angle")); + EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle")); shadow_angle = new DoubleField(shadow_angle_row, "shadowangle"); shadow_angle->SetColumnSpan(2); - EffectRow* shadow_distance_row = add_row(tr("Shadow Distance")); + EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance")); shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance"); shadow_distance->SetColumnSpan(2); shadow_distance->SetMinimum(0); - EffectRow* shadow_softness_row = add_row(tr("Shadow Softness")); + EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness")); shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness"); shadow_softness->SetColumnSpan(2); shadow_softness->SetMinimum(0); - EffectRow* shadow_opacity_row = add_row(tr("Shadow Opacity")); + EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity")); shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity"); shadow_opacity->SetColumnSpan(2); shadow_opacity->SetMinimum(0); @@ -145,7 +145,7 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : fragPath = "dropshadow.frag"; } -void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) { +void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly) { int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index c69041954..b10b9d916 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -49,41 +49,41 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : SetAlwaysUpdate(true); SetFlags(Effect::SuperimposeFlag); - EffectRow* tc_row = add_row(tr("Timecode")); + EffectRow* tc_row = new EffectRow(this, tr("Timecode")); tc_select = new ComboField(tc_row, "tc_selector"); tc_select->AddItem(tr("Sequence"), true); tc_select->AddItem(tr("Media"), false); tc_select->SetValueAt(0, true); - EffectRow* scale_row = add_row(tr("Scale")); + EffectRow* scale_row = new EffectRow(this, tr("Scale")); scale_val = new DoubleField(scale_row, "scale"); scale_val->SetColumnSpan(2); scale_val->SetMinimum(1); scale_val->SetDefault(100); scale_val->SetMaximum(1000); - EffectRow* color_row = add_row(tr("Color")); + EffectRow* color_row = new EffectRow(this, tr("Color")); color_val = new ColorField(color_row, "color"); color_val->SetColumnSpan(2); color_val->SetValueAt(0, QColor(Qt::white)); - EffectRow* color_bg_row = add_row(tr("Background Color")); + EffectRow* color_bg_row = new EffectRow(this, tr("Background Color")); color_bg_val = new ColorField(color_bg_row, "bgcolor"); color_bg_val->SetColumnSpan(2); color_bg_val->SetValueAt(0, QColor(Qt::black)); - EffectRow* bg_alpha_row = add_row(tr("Background Opacity")); + EffectRow* bg_alpha_row = new EffectRow(this, tr("Background Opacity")); bg_alpha = new DoubleField(bg_alpha_row, "bgalpha"); bg_alpha->SetColumnSpan(2); bg_alpha->SetMinimum(0); bg_alpha->SetDefault(50); bg_alpha->SetMaximum(100); - EffectRow* offset_row = add_row(tr("Offset")); + EffectRow* offset_row = new EffectRow(this, tr("Offset")); offset_x_val = new DoubleField(offset_row, "offsetx"); offset_y_val = new DoubleField(offset_row, "offsety"); - EffectRow* prepent_text_row = add_row(tr("Prepend")); + EffectRow* prepent_text_row = new EffectRow(this, tr("Prepend")); prepend_text = new StringField(prepent_text_row, "prepend"); prepend_text->SetColumnSpan(2); } diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp index 132112a98..95c33504d 100644 --- a/effects/internal/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -29,23 +29,23 @@ #include "debug.h" ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) { - EffectRow* type_row = add_row(tr("Type")); + EffectRow* type_row = new EffectRow(this, tr("Type")); type_val = new ComboField(type_row, "type"); type_val->AddItem(tr("Sine"), TONE_TYPE_SINE); - EffectRow* frequency_row = add_row(tr("Frequency")); + EffectRow* frequency_row = new EffectRow(this, tr("Frequency")); freq_val = new DoubleField(frequency_row, "frequency"); freq_val->SetMinimum(20); freq_val->SetMaximum(20000); freq_val->SetDefault(1000); - EffectRow* amount_row = add_row(tr("Amount")); + EffectRow* amount_row = new EffectRow(this, tr("Amount")); amount_val = new DoubleField(amount_row, "amount"); amount_val->SetMinimum(0); amount_val->SetMaximum(100); amount_val->SetDefault(25); - EffectRow* mix_row = add_row(tr("Mix")); + EffectRow* mix_row = new EffectRow(this, tr("Mix")); mix_val = new BoolField(mix_row, "mix"); mix_val->SetValueAt(0, true); } diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 0662bc0d1..4043f2ba0 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -46,12 +46,12 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { SetFlags(Effect::CoordsFlag); - EffectRow* position_row = add_row(tr("Position")); + EffectRow* position_row = new EffectRow(this, tr("Position")); position_x = new DoubleField(position_row, "posx"); // position X position_y = new DoubleField(position_row, "posy"); // position Y - EffectRow* scale_row = add_row(tr("Scale")); + EffectRow* scale_row = new EffectRow(this, tr("Scale")); // scale X (and Y is uniform scale is selected) scale_x = new DoubleField(scale_row, "scalex"); @@ -61,27 +61,27 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) scale_y = new DoubleField(scale_row, "scaley"); scale_y->SetMinimum(0); - EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); + EffectRow* uniform_scale_row = new EffectRow(this, tr("Uniform Scale")); uniform_scale_field = new BoolField(uniform_scale_row, "uniformscale"); // uniform scale option - EffectRow* rotation_row = add_row(tr("Rotation")); + EffectRow* rotation_row = new EffectRow(this, tr("Rotation")); rotation = new DoubleField(rotation_row, "rotation"); - EffectRow* anchor_point_row = add_row(tr("Anchor Point")); + EffectRow* anchor_point_row = new EffectRow(this, tr("Anchor Point")); anchor_x_box = new DoubleField(anchor_point_row, "anchorx"); // anchor point X anchor_y_box = new DoubleField(anchor_point_row, "anchory"); // anchor point Y - EffectRow* opacity_row = add_row(tr("Opacity")); + EffectRow* opacity_row = new EffectRow(this, tr("Opacity")); // opacity opacity = new DoubleField(opacity_row, "opacity"); opacity->SetMinimum(0); opacity->SetMaximum(100); - EffectRow* blend_mode_row = add_row(tr("Blend Mode")); + EffectRow* blend_mode_row = new EffectRow(this, tr("Blend Mode")); // blend mode blend_mode_box = new ComboField(blend_mode_row, "blendmode"); diff --git a/effects/internal/voideffect.cpp b/effects/internal/voideffect.cpp index de7aaa293..49c71eff8 100644 --- a/effects/internal/voideffect.cpp +++ b/effects/internal/voideffect.cpp @@ -28,36 +28,38 @@ #include "debug.h" VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) { - name = n; - QString display_name; - if (n.isEmpty()) { - display_name = tr("(unknown)"); - } else { - display_name = n; - } - EffectRow* row = add_row(tr("Missing Effect"), false, false); - row->add_widget(new QLabel(display_name)); - container->setText(display_name); + name = n; + QString display_name; + if (n.isEmpty()) { + display_name = tr("(unknown)"); + } else { + display_name = n; + } + EffectRow* row = new EffectRow(this, tr("Missing Effect"), false, false); - void_meta.type = EFFECT_TYPE_EFFECT; - meta = &void_meta; + new LabelField(row, display_name); + + container->setText(display_name); + + void_meta.type = EFFECT_TYPE_EFFECT; + meta = &void_meta; } EffectPtr VoidEffect::copy(Clip* c) { EffectPtr copy(new VoidEffect(c, name)); - copy->set_enabled(is_enabled()); - copy_field_keyframes(copy); - return copy; + copy->set_enabled(is_enabled()); + copy_field_keyframes(copy); + return copy; } void VoidEffect::load(QXmlStreamReader &stream) { - QString tag = stream.name().toString(); + QString tag = stream.name().toString(); QXmlStreamWriter writer(&bytes); // copy XML from reader to writer while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { - stream.readNext(); + stream.readNext(); if (stream.isStartElement()) { writer.writeStartElement(stream.name().toString()); @@ -75,18 +77,18 @@ void VoidEffect::load(QXmlStreamReader &stream) { } void VoidEffect::save(QXmlStreamWriter &stream) { - if (!name.isEmpty()) { - stream.writeAttribute("name", name); - stream.writeAttribute("enabled", QString::number(is_enabled())); + if (!name.isEmpty()) { + stream.writeAttribute("name", name); + stream.writeAttribute("enabled", QString::number(is_enabled())); - // force xml writer to expand tag, ignored when loading - stream.writeStartElement("void"); - stream.writeEndElement(); + // force xml writer to expand tag, ignored when loading + stream.writeStartElement("void"); + stream.writeEndElement(); - if (!bytes.isEmpty()) { - // write stored data - QIODevice* device = stream.device(); - device->write(bytes); - } - } + if (!bytes.isEmpty()) { + // write stored data + QIODevice* device = stream.device(); + device->write(bytes); + } + } } diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp index a08427a41..1b12216f5 100644 --- a/effects/internal/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -29,7 +29,7 @@ #include "ui/collapsiblewidget.h" VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - EffectRow* volume_row = add_row(tr("Volume")); + EffectRow* volume_row = new EffectRow(this, tr("Volume")); volume_val = new DoubleField(volume_row, "volume"); // set defaults diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index aa38f2470..c29f9c550 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -266,16 +266,17 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) { outputs[channel] = new float[BLOCK_SIZE]; } - EffectRow* file_row = add_row(tr("Plugin"), true, false); + EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false); file_field = new FileField(file_row, "filename"); connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin())); - EffectRow* interface_row = add_row(tr("Interface"), false, false); - show_interface_btn = new QPushButton(tr("Show")); - show_interface_btn->setCheckable(true); - show_interface_btn->setEnabled(false); + EffectRow* interface_row = new EffectRow(this, tr("Interface"), false, false); + + + show_interface_btn = new ButtonField(interface_row, tr("Show")); + show_interface_btn->SetCheckable(true); + show_interface_btn->SetEnabled(false); connect(show_interface_btn, SIGNAL(toggled(bool)), this, SLOT(show_interface(bool))); - interface_row->add_widget(show_interface_btn); dialog = new QDialog(olive::MainWindow); dialog->setWindowTitle(tr("VST Plugin")); @@ -373,7 +374,7 @@ void VSTHost::show_interface(bool show) { } void VSTHost::uncheck_show_button() { - show_interface_btn->setChecked(false); + show_interface_btn->SetChecked(false); } void VSTHost::change_plugin() { @@ -395,7 +396,7 @@ void VSTHost::change_plugin() { plugin = nullptr; } } - show_interface_btn->setEnabled(plugin != nullptr); + show_interface_btn->SetEnabled(plugin != nullptr); } #endif diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index cebd2e11d..5ac307139 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -37,7 +37,7 @@ typedef intptr_t (*dispatcherFuncPtr)(AEffect *effect, int32_t opCode, int32_t i class VSTHost : public Effect { Q_OBJECT public: - VSTHost(Clip* c, const EffectMeta* em); + VSTHost(Clip* c, const EffectMeta* em); ~VSTHost(); void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); @@ -49,6 +49,7 @@ private slots: void change_plugin(); private: FileField* file_field; + ButtonField* show_interface_btn; void loadPlugin(); void freePlugin(); @@ -64,7 +65,6 @@ private: float** inputs; float** outputs; QDialog* dialog; - QPushButton* show_interface_btn; QByteArray data_cache; #if defined(__APPLE__) diff --git a/olive.pro b/olive.pro index a826f8380..87d239992 100644 --- a/olive.pro +++ b/olive.pro @@ -168,7 +168,9 @@ SOURCES += \ project/effectfields/stringfield.cpp \ project/effectfields/boolfield.cpp \ project/effectfields/combofield.cpp \ - project/effectfields/filefield.cpp + project/effectfields/filefield.cpp \ + project/effectfields/labelfield.cpp \ + project/effectfields/buttonfield.cpp HEADERS += \ mainwindow.h \ @@ -290,7 +292,9 @@ HEADERS += \ project/effectfields/stringfield.h \ project/effectfields/boolfield.h \ project/effectfields/combofield.h \ - project/effectfields/filefield.h + project/effectfields/filefield.h \ + project/effectfields/labelfield.h \ + project/effectfields/buttonfield.h FORMS += diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index 4f5806aaf..cfe9d6723 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -141,11 +141,11 @@ void GraphEditor::update_panel() { if (isVisible()) { if (row != nullptr) { int slider_index = 0; - for (int i=0;ifieldCount();i++) { - EffectField* field = row->field(i); + for (int i=0;iFieldCount();i++) { + EffectField* field = row->Field(i); if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { slider_proxies.at(slider_index)->set_value( - row->field(i)->GetValueAt(playhead_to_clip_seconds(field->GetParentRow()->parent_effect->parent_clip, + row->Field(i)->GetValueAt(playhead_to_clip_seconds(field->GetParentRow()->GetParentEffect()->parent_clip, olive::ActiveSequence->playhead)).toDouble(), false ); @@ -177,9 +177,9 @@ void GraphEditor::set_row(EffectRow *r) { bool found_vals = false; - if (r != nullptr && r->isKeyframing()) { - for (int i=0;ifieldCount();i++) { - EffectField* field = r->field(i); + if (r != nullptr && r->IsKeyframing()) { + for (int i=0;iFieldCount();i++) { + EffectField* field = r->Field(i); if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { QPushButton* slider_button = new QPushButton(); slider_button->setCheckable(true); @@ -192,7 +192,7 @@ void GraphEditor::set_row(EffectRow *r) { value_layout->addWidget(slider_button); LabelSlider* slider = new LabelSlider(); - slider->set_color(get_curve_color(i, r->fieldCount()).name()); + 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); @@ -206,10 +206,10 @@ void GraphEditor::set_row(EffectRow *r) { if (found_vals) { row = r; - current_row_desc->setText(row->parent_effect->parent_clip->name() - + " :: " + row->parent_effect->meta->name + current_row_desc->setText(row->GetParentEffect()->parent_clip->name() + + " :: " + row->GetParentEffect()->meta->name + " :: " + row->name()); - header->set_visible_in(r->parent_effect->parent_clip->timeline_in()); + header->set_visible_in(r->GetParentEffect()->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())); diff --git a/project/clip.cpp b/project/clip.cpp index aaf532da3..cf85fb55c 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -442,8 +442,8 @@ void Clip::refactor_frame_rate(ComboAction* ca, double multiplier, bool change_t EffectPtr e = effects.at(i); for (int j=0;jrow_count();j++) { EffectRow* r = e->row(j); - for (int l=0;lfieldCount();l++) { - EffectField* f = r->field(l); + for (int l=0;lFieldCount();l++) { + EffectField* f = r->Field(l); for (int k=0;kkeyframes.size();k++) { ca->append(new SetLong(&f->keyframes[k].time, f->keyframes[k].time, qRound(f->keyframes[k].time * multiplier))); } diff --git a/project/effect.cpp b/project/effect.cpp index a437bf125..74f41bf94 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -153,7 +153,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) : } } if (!row_name.isEmpty()) { - EffectRow* row = add_row(row_name); + EffectRow* row = new EffectRow(this, row_name); while (!reader.atEnd() && !(reader.name() == "row" && reader.isEndElement())) { reader.readNext(); if (reader.name() == "field" && reader.isStartElement()) { @@ -356,9 +356,6 @@ Effect::~Effect() { delete container; - for (int i=0;irows.at(i); - copy_row->setKeyframing(row->isKeyframing()); - for (int j=0;jfieldCount();j++) { + copy_row->SetKeyframing(row->IsKeyframing()); + for (int j=0;jFieldCount();j++) { // Get field from this (the source) effect - EffectField* field = row->field(j); + EffectField* field = row->Field(j); // Get field from the destination effect - EffectField* copy_field = copy_row->field(j); + EffectField* copy_field = copy_row->Field(j); // Copy keyframes between effects copy_field->keyframes = field->keyframes; @@ -382,12 +379,6 @@ void Effect::copy_field_keyframes(EffectPtr e) { } } -EffectRow* Effect::add_row(const QString& name, bool savable, bool keyframable) { - EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); - rows.append(row); - return row; -} - EffectRow* Effect::row(int i) { return rows.at(i); } @@ -575,30 +566,30 @@ void Effect::load(QXmlStreamReader& stream) { if (stream.name() == "row" && stream.isStartElement()) { if (row_count < rows.size()) { EffectRow* row = rows.at(row_count); - int field_count = 0; while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { stream.readNext(); // read field if (stream.name() == "field" && stream.isStartElement()) { - if (field_count < row->fieldCount()) { - // match field using ID - int field_number = field_count; - for (int k=0;kfieldCount();l++) { - if (row->field(l)->id() == attr.value()) { - field_number = l; - break; - } - } - break; - } - } + int field_number = -1; - EffectField* field = row->field(field_number); + // match field using ID + for (int k=0;kFieldCount();l++) { + if (row->Field(l)->id() == attr.value()) { + field_number = l; + break; + } + } + break; + } + } + + if (field_number > -1) { + EffectField* field = row->Field(field_number); // get current field value /* @@ -616,7 +607,7 @@ void Effect::load(QXmlStreamReader& stream) { // read keyframes if (stream.name() == "key" && stream.isStartElement()) { - row->setKeyframing(true); + row->SetKeyframing(true); EffectKeyframe key; for (int k=0;kkeyframes.append(key); } } - } else { - qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; } - field_count++; } } @@ -665,25 +653,28 @@ void Effect::save(QXmlStreamWriter& stream) { for (int i=0;isavable) { + if (row->IsSavable()) { stream.writeStartElement("row"); // row - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - stream.writeStartElement("field"); // field - stream.writeAttribute("id", field->id()); - for (int k=0;kkeyframes.size();k++) { - const EffectKeyframe& key = field->keyframes.at(k); - stream.writeStartElement("key"); - stream.writeAttribute("value", field->ConvertValueToString(key.data)); - stream.writeAttribute("frame", QString::number(key.time)); - stream.writeAttribute("type", QString::number(key.type)); - stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); - stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); - stream.writeAttribute("posthx", QString::number(key.post_handle_x)); - stream.writeAttribute("posthy", QString::number(key.post_handle_y)); - stream.writeEndElement(); // key + for (int j=0;jFieldCount();j++) { + EffectField* field = row->Field(j); + + if (field->id().isEmpty()) { + stream.writeStartElement("field"); // field + stream.writeAttribute("id", field->id()); + for (int k=0;kkeyframes.size();k++) { + const EffectKeyframe& key = field->keyframes.at(k); + stream.writeStartElement("key"); + stream.writeAttribute("value", field->ConvertValueToString(key.data)); + stream.writeAttribute("frame", QString::number(key.time)); + stream.writeAttribute("type", QString::number(key.type)); + stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); + stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); + stream.writeAttribute("posthx", QString::number(key.post_handle_x)); + stream.writeAttribute("posthy", QString::number(key.post_handle_y)); + stream.writeEndElement(); // key + } + stream.writeEndElement(); // field } - stream.writeEndElement(); // field } stream.writeEndElement(); // row } @@ -694,9 +685,9 @@ void Effect::load_from_string(const QByteArray &s) { // clear existing keyframe data for (int i=0;isetKeyframing(false); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); + row->SetKeyframing(false); + for (int j=0;jFieldCount();j++) { + EffectField* field = row->Field(j); field->keyframes.clear(); } } @@ -884,8 +875,8 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); + for (int j=0;jFieldCount();j++) { + EffectField* field = row->Field(j); if (!field->id().isEmpty()) { switch (field->type()) { case EffectField::EFFECT_FIELD_DOUBLE: @@ -1070,8 +1061,8 @@ bool Effect::valueHasChanged(double timecode) { for (int i=0;ifieldCount();j++) { - cachedValues.append(crow->field(j)->GetValueAt(timecode)); + for (int j=0;jFieldCount();j++) { + cachedValues.append(crow->Field(j)->GetValueAt(timecode)); } } return true; @@ -1082,8 +1073,8 @@ bool Effect::valueHasChanged(double timecode) { int index = 0; for (int i=0;ifieldCount();j++) { - EffectField* field = crow->field(j); + for (int j=0;jFieldCount();j++) { + EffectField* field = crow->Field(j); if (cachedValues.at(index) != field->GetValueAt(timecode)) { changed = true; } diff --git a/project/effect.h b/project/effect.h index dea03233c..536443995 100644 --- a/project/effect.h +++ b/project/effect.h @@ -145,7 +145,6 @@ public: QString name; CollapsibleWidget* container; - EffectRow* add_row(const QString &name, bool savable = true, bool keyframable = true); EffectRow* row(int i); int row_count(); diff --git a/project/effectfields.h b/project/effectfields.h index 668108ae6..c05a3d4df 100644 --- a/project/effectfields.h +++ b/project/effectfields.h @@ -2,11 +2,13 @@ #define EFFECTFIELDS_H #include "effectfields/boolfield.h" +#include "effectfields/buttonfield.h" #include "effectfields/colorfield.h" #include "effectfields/combofield.h" #include "effectfields/doublefield.h" #include "effectfields/filefield.h" #include "effectfields/fontfield.h" +#include "effectfields/labelfield.h" #include "effectfields/stringfield.h" #endif // EFFECTFIELDS_H diff --git a/project/effectfields/boolfield.h b/project/effectfields/boolfield.h index ee3fd848c..d61ef33e9 100644 --- a/project/effectfields/boolfield.h +++ b/project/effectfields/boolfield.h @@ -11,8 +11,8 @@ public: bool GetBoolAt(double timecode); - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); + virtual QVariant ConvertStringToValue(const QString& s) override; + virtual QString ConvertValueToString(const QVariant& v) override; }; #endif // BOOLFIELD_H diff --git a/project/effectfields/buttonfield.cpp b/project/effectfields/buttonfield.cpp new file mode 100644 index 000000000..28865d62f --- /dev/null +++ b/project/effectfields/buttonfield.cpp @@ -0,0 +1,18 @@ +#include "buttonfield.h" + +ButtonField::ButtonField(EffectRow *parent, const QString &string) : + EffectField(parent, nullptr, EFFECT_FIELD_UI) +{ + SetValueAt(0, string); +} + +void ButtonField::SetCheckable(bool c) +{ + checkable_ = c; +} + +void ButtonField::SetChecked(bool c) +{ + checked_ = c; + emit CheckedChanged(c); +} diff --git a/project/effectfields/buttonfield.h b/project/effectfields/buttonfield.h new file mode 100644 index 000000000..eb108427c --- /dev/null +++ b/project/effectfields/buttonfield.h @@ -0,0 +1,21 @@ +#ifndef BUTTONFIELD_H +#define BUTTONFIELD_H + +#include "effectfield.h" + +class ButtonField : public EffectField +{ + Q_OBJECT +public: + ButtonField(EffectRow* parent, const QString& string); + + void SetCheckable(bool c); + void SetChecked(bool c); +signals: + void CheckedChanged(bool); +private: + bool checkable_; + bool checked_; +}; + +#endif // BUTTONFIELD_H diff --git a/project/effectfields/colorfield.h b/project/effectfields/colorfield.h index 91b4b8a7a..26f668c65 100644 --- a/project/effectfields/colorfield.h +++ b/project/effectfields/colorfield.h @@ -11,8 +11,8 @@ public: QColor GetColorAt(double timecode); - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); + virtual QVariant ConvertStringToValue(const QString& s) override; + virtual QString ConvertValueToString(const QVariant& v) override; }; #endif // COLORFIELD_H diff --git a/project/effectfields/combofield.cpp b/project/effectfields/combofield.cpp index 342dd6a21..301b1f8f2 100644 --- a/project/effectfields/combofield.cpp +++ b/project/effectfields/combofield.cpp @@ -13,13 +13,3 @@ void ComboField::AddItem(const QString &text, const QVariant &data) items_.append(item); } - -QVariant ComboField::ConvertStringToValue(const QString &s) -{ - return s; -} - -QString ComboField::ConvertValueToString(const QVariant &v) -{ - return v.toString(); -} diff --git a/project/effectfields/combofield.h b/project/effectfields/combofield.h index 00c229259..26afd90b3 100644 --- a/project/effectfields/combofield.h +++ b/project/effectfields/combofield.h @@ -16,9 +16,6 @@ public: void AddItem(const QString& text, const QVariant& data); - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); - signals: void IndexChanged(int i); diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp index 96d32366b..bb0536f20 100644 --- a/project/effectfields/effectfield.cpp +++ b/project/effectfields/effectfield.cpp @@ -52,7 +52,7 @@ EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) { // EffectField MUST be created with a parent. Q_ASSERT(parent != nullptr); - Q_ASSERT(!i.isEmpty()); + Q_ASSERT(!i.isEmpty() || t == EFFECT_FIELD_UI); parent->AddField(this); /* @@ -141,6 +141,16 @@ void EffectField::SetColumnSpan(int i) colspan_ = i; } +QVariant EffectField::ConvertStringToValue(const QString &s) +{ + return s; +} + +QString EffectField::ConvertValueToString(const QVariant &v) +{ + return v.toString(); +} + QVariant EffectField::GetValueAt(double timecode) { Q_ASSERT(!keyframes.isEmpty()); @@ -172,15 +182,15 @@ QVariant EffectField::GetValueAt(double timecode) // bezier interpolation if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { // cubic bezier - double t = cubic_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); + double t = cubic_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), 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); } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier // last keyframe is the bezier one - double t = quad_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time); + double t = quad_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time); value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t); } else { // this keyframe is the bezier one - double t = quad_t_from_x(timecode*GetParentRow()->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); + double t = quad_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t); } } else { @@ -223,7 +233,7 @@ void EffectField::SetValueAt(double timecode, const QVariant &value) return; } - if (GetParentRow()->isKeyframing()) { + if (GetParentRow()->IsKeyframing()) { // create keyframe here } else { keyframes.first().data = value; @@ -289,11 +299,11 @@ double EffectField::GetValidKeyframeHandlePosition(int key, bool post) { } double EffectField::frameToTimecode(long frame) { - return (double(frame) / GetParentRow()->parent_effect->parent_clip->sequence->frame_rate); + return (double(frame) / GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); } long EffectField::timecodeToFrame(double timecode) { - return qRound(timecode * GetParentRow()->parent_effect->parent_clip->sequence->frame_rate); + return qRound(timecode * GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); } void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { @@ -333,7 +343,7 @@ void EffectField::get_keyframe_data(double timecode, int &before, int &after, do } bool EffectField::HasKeyframes() { - return (GetParentRow()->isKeyframing() && keyframes.size() > 1); + return (GetParentRow()->IsKeyframing() && keyframes.size() > 1); } void EffectField::ui_element_change() { diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h index f5725e724..c413078a7 100644 --- a/project/effectfields/effectfield.h +++ b/project/effectfields/effectfield.h @@ -40,7 +40,8 @@ public: EFFECT_FIELD_BOOL, EFFECT_FIELD_COMBO, EFFECT_FIELD_FONT, - EFFECT_FIELD_FILE + EFFECT_FIELD_FILE, + EFFECT_FIELD_UI }; EffectField(EffectRow* parent, const QString& i, EffectFieldType t); @@ -57,8 +58,8 @@ public: int GetColumnSpan(); void SetColumnSpan(int i); - virtual QVariant ConvertStringToValue(const QString& s) = 0; - virtual QString ConvertValueToString(const QVariant& v) = 0; + virtual QVariant ConvertStringToValue(const QString& s); + virtual QString ConvertValueToString(const QVariant& v); double GetValidKeyframeHandlePosition(int key, bool post); diff --git a/project/effectfields/filefield.cpp b/project/effectfields/filefield.cpp index 594cd6ff7..7ba52482e 100644 --- a/project/effectfields/filefield.cpp +++ b/project/effectfields/filefield.cpp @@ -10,13 +10,3 @@ QString FileField::GetFileAt(double timecode) { return GetValueAt(timecode).toString(); } - -QVariant FileField::ConvertStringToValue(const QString &s) -{ - return s; -} - -QString FileField::ConvertValueToString(const QVariant &v) -{ - return v.toString(); -} diff --git a/project/effectfields/filefield.h b/project/effectfields/filefield.h index edfcb280f..575a43c21 100644 --- a/project/effectfields/filefield.h +++ b/project/effectfields/filefield.h @@ -10,9 +10,6 @@ public: FileField(EffectRow* parent, const QString& id); QString GetFileAt(double timecode); - - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); }; #endif // FILEFIELD_H diff --git a/project/effectfields/fontfield.cpp b/project/effectfields/fontfield.cpp index faf88c55e..7c16f2eea 100644 --- a/project/effectfields/fontfield.cpp +++ b/project/effectfields/fontfield.cpp @@ -10,13 +10,3 @@ QString FontField::GetFontAt(double timecode) { return GetValueAt(timecode).toString(); } - -QVariant FontField::ConvertStringToValue(const QString &s) -{ - return s; -} - -QString FontField::ConvertValueToString(const QVariant &v) -{ - return v.toString(); -} diff --git a/project/effectfields/fontfield.h b/project/effectfields/fontfield.h index cf5b36c35..532f82d4d 100644 --- a/project/effectfields/fontfield.h +++ b/project/effectfields/fontfield.h @@ -9,9 +9,6 @@ public: FontField(EffectRow* parent, const QString& id); QString GetFontAt(double timecode); - - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); }; #endif // FONTFIELD_H diff --git a/project/effectfields/labelfield.cpp b/project/effectfields/labelfield.cpp new file mode 100644 index 000000000..bf6db9238 --- /dev/null +++ b/project/effectfields/labelfield.cpp @@ -0,0 +1,7 @@ +#include "labelfield.h" + +LabelField::LabelField(EffectRow *parent, const QString &string) : + EffectField(parent, nullptr, EFFECT_FIELD_UI) +{ + SetValueAt(0, string); +} diff --git a/project/effectfields/labelfield.h b/project/effectfields/labelfield.h new file mode 100644 index 000000000..e7dd712f2 --- /dev/null +++ b/project/effectfields/labelfield.h @@ -0,0 +1,13 @@ +#ifndef LABELFIELD_H +#define LABELFIELD_H + +#include "effectfield.h" + +class LabelField : public EffectField +{ + Q_OBJECT +public: + LabelField(EffectRow* parent, const QString& string); +}; + +#endif // LABELFIELD_H diff --git a/project/effectfields/stringfield.cpp b/project/effectfields/stringfield.cpp index 77080607e..609a62362 100644 --- a/project/effectfields/stringfield.cpp +++ b/project/effectfields/stringfield.cpp @@ -10,13 +10,3 @@ QString StringField::GetStringAt(double timecode) { return GetValueAt(timecode).toString(); } - -QVariant StringField::ConvertStringToValue(const QString &s) -{ - return s; -} - -QString StringField::ConvertValueToString(const QVariant &v) -{ - return v.toString(); -} diff --git a/project/effectfields/stringfield.h b/project/effectfields/stringfield.h index 36028d891..a7ca70668 100644 --- a/project/effectfields/stringfield.h +++ b/project/effectfields/stringfield.h @@ -10,9 +10,6 @@ public: StringField(EffectRow* parent, const QString& id); QString GetStringAt(double timecode); - - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); }; #endif // STRINGFIELD_H diff --git a/project/effectrow.cpp b/project/effectrow.cpp index 51a3a429b..2558ee326 100644 --- a/project/effectrow.cpp +++ b/project/effectrow.cpp @@ -36,41 +36,14 @@ #include "ui/keyframenavigator.h" #include "ui/clickablelabel.h" -EffectRow::EffectRow(Effect *parent, bool save, QGridLayout *uilayout, const QString &n, int row, bool keyframable) : - parent_effect(parent), - savable(save), - keyframing(false), - ui(uilayout), +EffectRow::EffectRow(Effect *parent, const QString &n, bool savable, bool keyframable) : + QObject(parent), name_(n), - ui_row(row), - just_made_unsafe_keyframe(false) + keyframable_(keyframable), + keyframing_(false), + savable_(savable) { - label = new ClickableLabel(name_ + ":"); - - ui->addWidget(label, row, 0); - - column_count = 1; - - keyframe_nav = nullptr; - if (parent_effect->meta != nullptr - && parent_effect->meta->type != EFFECT_TYPE_TRANSITION - && keyframable) { - connect(label, SIGNAL(clicked()), this, SLOT(FocusRow())); - - keyframe_nav = new KeyframeNavigator(); - connect(keyframe_nav, SIGNAL(GoToPreviousKeyframe()), this, SLOT(GoToPreviousKeyframe())); - connect(keyframe_nav, SIGNAL(ToggleKeyframe()), this, SLOT(ToggleKeyframe())); - connect(keyframe_nav, SIGNAL(GoToNextKeyframe()), this, SLOT(GoToNextKeyframe())); - connect(keyframe_nav, SIGNAL(keyframe_enabled_changed(bool)), this, SLOT(SetKeyframingEnabled(bool))); - connect(keyframe_nav, SIGNAL(clicked()), this, SLOT(FocusRow())); - ui->addWidget(keyframe_nav, row, 6); - } -} - -EffectRow::~EffectRow() { - for (int i=0;imeta->type != EFFECT_TYPE_TRANSITION) { - keyframing = b; - if (keyframe_nav != nullptr) { - keyframe_nav->enable_keyframes(b); - } +void EffectRow::SetKeyframing(bool b) { + if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) { + keyframing_ = b; + emit KeyframingSetChanged(keyframing_); } } +bool EffectRow::IsSavable() +{ + return savable_; +} + void EffectRow::SetKeyframingEnabled(bool enabled) { if (enabled) { ComboAction* ca = new ComboAction(); - ca->append(new SetKeyframing(this, true)); + ca->append(new SetIsKeyframing(this, true)); set_keyframe_now(ca); olive::UndoStack.push(ca); } else { if (QMessageBox::question(panel_effect_controls, - tr("Disable Keyframes"), - tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { + tr("Disable Keyframes"), + tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { // clear ComboAction* ca = new ComboAction(); - for (int i=0;ikeyframes.size();j++) { ca->append(new KeyframeDelete(f, 0)); } } - ca->append(new SetKeyframing(this, false)); + ca->append(new SetIsKeyframing(this, false)); olive::UndoStack.push(ca); panel_effect_controls->update_keyframes(); } else { - setKeyframing(true); + SetKeyframing(true); } } } void EffectRow::GoToPreviousKeyframe() { long key = LONG_MIN; - Clip* c = parent_effect->parent_clip; - for (int i=0;iparent_clip; + for (int i=0;ikeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); if (comp < olive::ActiveSequence->playhead) { @@ -138,9 +114,9 @@ void EffectRow::GoToPreviousKeyframe() { void EffectRow::ToggleKeyframe() { QVector key_fields; QVector key_field_index; - Clip* c = parent_effect->parent_clip; - for (int j=0;jparent_clip; + for (int j=0;jkeyframes.size();i++) { long comp = c->timeline_in() - c->clip_in() + f->keyframes.at(i).time; if (comp == olive::ActiveSequence->playhead) { @@ -165,9 +141,9 @@ void EffectRow::ToggleKeyframe() { void EffectRow::GoToNextKeyframe() { long key = LONG_MAX; - Clip* c = parent_effect->parent_clip; - for (int i=0;iparent_clip; + for (int i=0;ikeyframes.size();j++) { long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); if (comp > olive::ActiveSequence->playhead) { @@ -182,25 +158,6 @@ void EffectRow::FocusRow() { panel_graph_editor->set_row(this); } -/* -EffectField* EffectRow::add_field(int type, const QString& id, int colspan) { - EffectField* field = new EffectField(this, type, id); - if (parent_effect->meta->type != EFFECT_TYPE_TRANSITION) connect(field, SIGNAL(clicked()), this, SLOT(focus_row())); - fields_.append(field); - QWidget* element = field->get_ui_element(); - ui->addWidget(element, ui_row, column_count, 1, colspan); - column_count++; - connect(field, SIGNAL(changed()), parent_effect, SLOT(field_changed())); - return field; -} -*/ - -void EffectRow::add_widget(QWidget* w) { - widgets.append(w); - ui->addWidget(w, ui_row, column_count); - column_count++; -} - void EffectRow::set_keyframe_now(ComboAction* ca) { // TODO address this... /* @@ -263,8 +220,8 @@ void EffectRow::set_keyframe_now(ComboAction* ca) { } void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) { - for (int j=0;jkeyframes.size();i++) { if (f->keyframes.at(i).time == time) { ca->append(new KeyframeDelete(f, i)); @@ -274,14 +231,19 @@ void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) { } } +Effect *EffectRow::GetParentEffect() +{ + return static_cast(parent()); +} + const QString &EffectRow::name() { return name_; } -EffectField* EffectRow::field(int i) { +EffectField* EffectRow::Field(int i) { return fields_.at(i); } -int EffectRow::fieldCount() { +int EffectRow::FieldCount() { return fields_.size(); } diff --git a/project/effectrow.h b/project/effectrow.h index 9b61ac6c3..a59486941 100644 --- a/project/effectrow.h +++ b/project/effectrow.h @@ -39,46 +39,40 @@ class ClickableLabel; class EffectRow : public QObject { Q_OBJECT public: - EffectRow(Effect* parent, bool save, QGridLayout* uilayout, const QString& n, int row, bool keyframable = true); - ~EffectRow(); + EffectRow(Effect* parent, const QString& n, bool savable = true, bool keyframable = true); - void AddField(EffectField* field); + void AddField(EffectField* Field); - void add_widget(QWidget *w); - EffectField* field(int i); - int fieldCount(); + EffectField* Field(int i); + int FieldCount(); void set_keyframe_now(ComboAction *ca); void delete_keyframe_at_time(ComboAction *ca, long time); - ClickableLabel* label; - Effect* parent_effect; - bool savable; + + Effect* GetParentEffect(); + const QString& name(); - bool isKeyframing(); - void setKeyframing(bool); + bool IsKeyframing(); + void SetKeyframing(bool); + + bool IsSavable(); public slots: void GoToPreviousKeyframe(); void ToggleKeyframe(); void GoToNextKeyframe(); void FocusRow(); +signals: + void KeyframingSetChanged(bool); private slots: void SetKeyframingEnabled(bool); private: - bool keyframing; - QGridLayout* ui; QString name_; - int ui_row; + + bool keyframable_; + bool keyframing_; + bool savable_; + QVector fields_; - QVector widgets; - - KeyframeNavigator* keyframe_nav; - - bool just_made_unsafe_keyframe; - QVector unsafe_keys; - QVector unsafe_old_data; - QVector key_is_new; - - int column_count; }; #endif // EFFECTROW_H diff --git a/project/transition.cpp b/project/transition.cpp index ecc53eb27..aaf1b811c 100644 --- a/project/transition.cpp +++ b/project/transition.cpp @@ -45,7 +45,7 @@ Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : Effect(c, em), secondary_clip(s) { - EffectRow* length_row = add_row(tr("Length"), false, false); + EffectRow* length_row = new EffectRow(this, tr("Length"), false, false); length_field = new DoubleField(length_row, "length"); length_field->SetDefault(30); length_field->SetMinimum(0); diff --git a/project/undo.cpp b/project/undo.cpp index fca7f6ff6..e34eb697d 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -1136,17 +1136,17 @@ void KeyframeFieldSet::doRedo() { done = true; } -SetKeyframing::SetKeyframing(EffectRow *irow, bool ib) { +SetIsKeyframing::SetIsKeyframing(EffectRow *irow, bool ib) { row = irow; b = ib; } -void SetKeyframing::doUndo() { - row->setKeyframing(!b); +void SetIsKeyframing::doUndo() { + row->SetKeyframing(!b); } -void SetKeyframing::doRedo() { - row->setKeyframing(b); +void SetIsKeyframing::doRedo() { + row->SetKeyframing(b); } RefreshClips::RefreshClips(Media *m) { diff --git a/project/undo.h b/project/undo.h index 273149794..efb9b9d4f 100644 --- a/project/undo.h +++ b/project/undo.h @@ -600,9 +600,9 @@ private: QVariant new_val; }; -class SetKeyframing : public OliveAction { +class SetIsKeyframing : public OliveAction { public: - SetKeyframing(EffectRow* irow, bool ib); + SetIsKeyframing(EffectRow* irow, bool ib); virtual void doUndo() override; virtual void doRedo() override; private: diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 3f51dda3f..bc08d2a6c 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -120,15 +120,15 @@ void GraphView::set_view_to_selection() { double min_dbl = DBL_MAX; double max_dbl = DBL_MIN; for (int i=0;ifield(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(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); } - min_time -= row->parent_effect->parent_clip->clip_in(); - max_time -= row->parent_effect->parent_clip->clip_in(); + min_time -= row->GetParentEffect()->parent_clip->clip_in(); + max_time -= row->GetParentEffect()->parent_clip->clip_in(); set_view_to_rect(min_time, min_dbl, max_time, max_dbl); } @@ -142,9 +142,9 @@ void GraphView::set_view_to_all() { long max_time = LONG_MIN; double min_dbl = DBL_MAX; double max_dbl = DBL_MIN; - for (int i=0;ifieldCount();i++) { - for (int j=0;jfield(i)->keyframes.size();j++) { - const EffectKeyframe& key = row->field(i)->keyframes.at(j); + for (int i=0;iFieldCount();i++) { + for (int j=0;jField(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); @@ -153,8 +153,8 @@ void GraphView::set_view_to_all() { } } if (can_set) { - min_time -= row->parent_effect->parent_clip->clip_in(); - max_time -= row->parent_effect->parent_clip->clip_in(); + min_time -= row->GetParentEffect()->parent_clip->clip_in(); + max_time -= row->GetParentEffect()->parent_clip->clip_in(); set_view_to_rect(min_time, min_dbl, max_time, max_dbl); } @@ -242,8 +242,8 @@ void GraphView::paintEvent(QPaintEvent *) { QPen line_pen; line_pen.setWidth(kBezierLineSize); - for (int i=row->fieldCount()-1;i>=0;i--) { - EffectField* field = row->field(i); + for (int i=row->FieldCount()-1;i>=0;i--) { + EffectField* field = row->Field(i); if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { // sort keyframes by time @@ -259,7 +259,7 @@ void GraphView::paintEvent(QPaintEvent *) { 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())); + 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); @@ -385,8 +385,8 @@ void GraphView::mousePressEvent(QMouseEvent *event) { update_ui(false); click_add_proc = true; } else { - for (int i=0;ifieldCount();i++) { - EffectField* field = row->field(i); + for (int i=0;iFieldCount();i++) { + EffectField* field = row->Field(i); if (field->type() == EffectField::EFFECT_FIELD_DOUBLE && field_visibility.at(i)) { for (int j=0;jkeyframes.size();j++) { const EffectKeyframe& key = field->keyframes.at(j); @@ -488,8 +488,8 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { selected_keys.resize(rect_select_offset); selected_keys_fields.resize(rect_select_offset); - for (int i=0;ifieldCount();i++) { - EffectField* f = row->field(i); + for (int i=0;iFieldCount();i++) { + EffectField* f = row->Field(i); for (int j=0;jkeyframes.size();j++) { bool already_selected = false; for (int k=0;kfield(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)].time = qRound(selected_keys_old_vals.at(i) + (double(event->pos().x() - start_x)/x_zoom)); + 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)/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); + 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())/y_zoom)); + 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())/y_zoom)); } } moved_keys = true; @@ -551,7 +551,7 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { } } - EffectKeyframe& key = row->field(handle_field)->keyframes[handle_index]; + EffectKeyframe& key = row->Field(handle_field)->keyframes[handle_index]; key.pre_handle_x = qMin(0.0, new_pre_handle_x); key.pre_handle_y = new_pre_handle_y; key.post_handle_x = qMax(0.0, new_post_handle_x); @@ -569,9 +569,9 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { bool hovering_key = false; - for (int i=0;ifieldCount();i++) { - for (int j=0;jfield(i)->keyframes.size();j++) { - const EffectKeyframe& key = row->field(i)->keyframes.at(j); + for (int i=0;iFieldCount();i++) { + for (int j=0;jField(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( @@ -603,8 +603,8 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { } if (!hovering_key) { - for (int i=0;ifieldCount();i++) { - EffectField* f = row->field(i); + for (int i=0;iFieldCount();i++) { + EffectField* f = row->Field(i); if (field_visibility.at(i)) { QVector sorted_keys = sort_keys_from_field(f); @@ -708,7 +708,7 @@ void GraphView::mouseReleaseEvent(QMouseEvent *) { switch (current_handle) { case kBezierHandleNone: for (int i=0;ifield(selected_keys_fields.at(i))->keyframes[selected_keys.at(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)); } @@ -716,7 +716,7 @@ void GraphView::mouseReleaseEvent(QMouseEvent *) { case kBezierHandlePre: case kBezierHandlePost: { - EffectKeyframe& key = row->field(handle_field)->keyframes[handle_index]; + 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)); @@ -831,11 +831,11 @@ void GraphView::set_row(EffectRow *r) { emit selection_changed(false, -1); row = r; if (row != nullptr) { - field_visibility.resize(row->fieldCount()); - for (int i=0;ifieldCount();i++) { - field_visibility[i] = row->field(i)->IsEnabled(); + field_visibility.resize(row->FieldCount()); + for (int i=0;iFieldCount();i++) { + field_visibility[i] = row->Field(i)->IsEnabled(); } - visible_in = row->parent_effect->parent_clip->timeline_in(); + visible_in = row->GetParentEffect()->parent_clip->timeline_in(); set_view_to_all(); } else { update(); @@ -847,7 +847,7 @@ void GraphView::set_selected_keyframe_type(int type) { if (selected_keys.size() > 0) { ComboAction* ca = new ComboAction(); for (int i=0;ifield(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)]; + EffectKeyframe& key = row->Field(selected_keys_fields.at(i))->keyframes[selected_keys.at(i)]; ca->append(new SetInt(&key.type, type)); } olive::UndoStack.push(ca); @@ -864,7 +864,7 @@ void GraphView::delete_selected_keys() { if (row != nullptr) { QVector fields; for (int i=0;ifield(selected_keys_fields.at(i))); + fields.append(row->Field(selected_keys_fields.at(i))); } delete_keyframes(fields, selected_keys); } @@ -874,8 +874,8 @@ void GraphView::select_all() { if (row != nullptr) { selected_keys.clear(); selected_keys_fields.clear(); - for (int i=0;ifieldCount();i++) { - EffectField* field = row->field(i); + for (int i=0;iFieldCount();i++) { + EffectField* field = row->Field(i); for (int j=0;jkeyframes.size();j++) { selected_keys.append(j); selected_keys_fields.append(i); @@ -903,7 +903,7 @@ void GraphView::set_zoom(double xz, double yz) { int GraphView::get_screen_x(double d) { if (row != nullptr) { - d -= row->parent_effect->parent_clip->clip_in(); + d -= row->GetParentEffect()->parent_clip->clip_in(); } return qRound((d*x_zoom) - x_scroll); } @@ -915,7 +915,7 @@ int GraphView::get_screen_y(double d) { long GraphView::get_value_x(int i) { long frame = qRound((i + x_scroll)/x_zoom); if (row != nullptr) { - frame += row->parent_effect->parent_clip->clip_in(); + frame += row->GetParentEffect()->parent_clip->clip_in(); } return frame; } @@ -931,7 +931,7 @@ void GraphView::selection_update() { int selected_key_type = -1; for (int i=0;ifield(selected_keys_fields.at(i))->keyframes.at(selected_keys.at(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()); diff --git a/ui/keyframedrawing.cpp b/ui/keyframedrawing.cpp index 734c658ee..e282cafdf 100644 --- a/ui/keyframedrawing.cpp +++ b/ui/keyframedrawing.cpp @@ -27,35 +27,35 @@ // routine for drawing a keyframe onscreen 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)); + 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 EFFECT_KEYFRAME_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 EFFECT_KEYFRAME_BEZIER: - p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE); - break; - case EFFECT_KEYFRAME_HOLD: - p.drawRect(QRect(x - KEYFRAME_SIZE, y - KEYFRAME_SIZE, KEYFRAME_SIZE*2, KEYFRAME_SIZE*2)); - break; - } + switch (type) { + case EFFECT_KEYFRAME_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 EFFECT_KEYFRAME_BEZIER: + p.drawEllipse(QPoint(x, y), KEYFRAME_SIZE, KEYFRAME_SIZE); + break; + case EFFECT_KEYFRAME_HOLD: + p.drawRect(QRect(x - KEYFRAME_SIZE, y - KEYFRAME_SIZE, KEYFRAME_SIZE*2, KEYFRAME_SIZE*2)); + break; + } - p.setBrush(Qt::NoBrush); + p.setBrush(Qt::NoBrush); } // adjusts keyframe's internal time (in clip time) to timeline time long adjust_row_keyframe(EffectRow* row, long time, long visible_in) { return time - - row->parent_effect->parent_clip->clip_in() - + (row->parent_effect->parent_clip->timeline_in() - visible_in); + - row->GetParentEffect()->parent_clip->clip_in() + + (row->GetParentEffect()->parent_clip->timeline_in() - visible_in); } diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 4c00dd862..dd36d8343 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -119,13 +119,22 @@ void KeyframeView::paintEvent(QPaintEvent*) { for (int j=0;jrow_count();j++) { EffectRow* row = e->row(j); + // TODO address this + + /* + ClickableLabel* label = row->label; QWidget* contents = e->container->contents; QVector 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*/; - for (int l=0;lfieldCount();l++) { - EffectField* f = row->field(l); + + 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(); + + for (int l=0;lFieldCount();l++) { + EffectField* f = row->Field(l); for (int k=0;kkeyframes.size();k++) { if (!key_times.contains(f->keyframes.at(k).time)) { bool keyframe_selected = keyframeIsSelected(f, k); @@ -133,8 +142,8 @@ void KeyframeView::paintEvent(QPaintEvent*) { // see if any other keyframes have this time int appearances = 0; - for (int m=0;mfieldCount();m++) { - EffectField* compf = row->field(m); + for (int m=0;mFieldCount();m++) { + EffectField* compf = row->Field(m); for (int n=0;nkeyframes.size();n++) { if (f->keyframes.at(k).time == compf->keyframes.at(n).time) { appearances++; @@ -142,8 +151,8 @@ void KeyframeView::paintEvent(QPaintEvent*) { } } - if (appearances != row->fieldCount()) { - QColor cc = get_curve_color(l, row->fieldCount()); + if (appearances != row->FieldCount()) { + 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); @@ -156,6 +165,8 @@ void KeyframeView::paintEvent(QPaintEvent*) { rows.append(row); rowY.append(keyframe_y); + + */ } } } @@ -252,10 +263,10 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { row->FocusRow(); - for (int k=0;kfieldCount();k++) { - EffectField* f = row->field(k); + for (int k=0;kFieldCount();k++) { + EffectField* f = row->Field(k); for (int j=0;jkeyframes.size();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); + long eval_keyframe_time = f->keyframes.at(j).time-row->GetParentEffect()->parent_clip->clip_in()+(row->GetParentEffect()->parent_clip->timeline_in()-visible_in); 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) { @@ -273,7 +284,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { bool already_selected = false; keys_selected = false; if (keyframe_index > -1) { - already_selected = keyframeIsSelected(rows.at(row_index)->field(field_index), keyframe_index); + already_selected = keyframeIsSelected(rows.at(row_index)->Field(field_index), keyframe_index); } else { select_rect = true; } @@ -283,14 +294,14 @@ void KeyframeView::mousePressEvent(QMouseEvent *event) { selected_keyframes.clear(); } if (keyframe_index > -1) { - selected_fields.append(rows.at(row_index)->field(field_index)); + selected_fields.append(rows.at(row_index)->Field(field_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;ifieldCount();i++) { + long comp_time = rows.at(row_index)->Field(field_index)->keyframes.at(keyframe_index).time; + for (int i=0;iFieldCount();i++) { if (i != field_index) { - EffectField* f = rows.at(row_index)->field(i); + EffectField* f = rows.at(row_index)->Field(i); for (int j=0;jkeyframes.size();j++) { if (f->keyframes.at(j).time == comp_time) { selected_fields.append(f); @@ -353,8 +364,8 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { for (int i=0;i= min_row && rowY.at(i) <= max_row) { EffectRow* row = rows.at(i); - for (int k=0;kfieldCount();k++) { - EffectField* field = row->field(k); + for (int k=0;kFieldCount();k++) { + EffectField* field = row->Field(k); for (int j=0;jkeyframes.size();j++) { long keyframe_frame = adjust_row_keyframe(row, field->keyframes.at(j).time, visible_in); if (!keyframeIsSelected(field, j) && keyframe_frame >= min_frame && keyframe_frame <= max_frame) { @@ -376,7 +387,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { if (panel_timeline->snapping) { for (int i=0;iGetParentRow()->parent_effect->parent_clip; + Clip* c = field->GetParentRow()->GetParentEffect()->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(olive::ActiveSequence->playhead, &key_eval)) { From 5b03af5e5acd42092ae14b34a9fd6cfaf4ac17f0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 12 Mar 2019 22:49:01 +1100 Subject: [PATCH 03/56] separated effect from UI --- dialogs/mediapropertiesdialog.cpp | 280 ++++++++++---------- dialogs/newsequencedialog.cpp | 368 +++++++++++++-------------- dialogs/newsequencedialog.h | 34 +-- dialogs/proxydialog.cpp | 4 +- effects/internal/voideffect.cpp | 39 ++- io/loadthread.cpp | 12 +- io/loadthread.h | 2 +- io/previewgenerator.h | 2 +- io/proxygenerator.cpp | 2 +- mainwindow.cpp | 2 +- olive.pro | 6 +- oliveglobal.cpp | 6 +- oliveglobal.h | 2 +- panels/effectcontrols.cpp | 295 +++++++++++---------- panels/effectcontrols.h | 44 ++-- panels/panels.cpp | 37 +-- panels/project.cpp | 29 ++- panels/timeline.cpp | 29 +-- panels/timeline.h | 6 +- panels/viewer.cpp | 32 +-- panels/viewer.h | 2 +- project/clip.cpp | 28 +- project/clip.h | 10 +- project/effect.cpp | 188 +++++--------- project/effect.h | 26 +- project/effectfields/doublefield.cpp | 5 + project/effectfields/doublefield.h | 2 + project/effectfields/effectfield.cpp | 5 + project/effectfields/effectfield.h | 2 + project/effectgizmo.cpp | 4 +- project/effectgizmo.h | 8 +- project/effectloaders.h | 8 + project/effectrow.cpp | 2 + project/marker.cpp | 124 ++++----- project/marker.h | 4 +- project/media.cpp | 28 +- project/media.h | 4 +- project/sequence.cpp | 10 +- project/sequence.h | 2 +- project/sourcescommon.cpp | 8 +- project/undo.cpp | 67 +++-- project/undo.h | 43 ++-- rendering/cacher.cpp | 8 +- rendering/renderfunctions.cpp | 10 +- rendering/renderfunctions.h | 6 +- rendering/renderthread.cpp | 7 +- rendering/renderthread.h | 4 +- ui/collapsiblewidget.cpp | 15 +- ui/collapsiblewidget.h | 19 +- ui/effectui.cpp | 94 +++++++ ui/effectui.h | 27 ++ ui/keyframeview.cpp | 90 +++---- ui/keyframeview.h | 82 +++--- ui/menuhelper.cpp | 23 +- ui/menuhelper.h | 9 + ui/timelineheader.cpp | 6 +- ui/timelinewidget.cpp | 14 +- ui/viewerwidget.cpp | 12 +- 58 files changed, 1166 insertions(+), 1071 deletions(-) create mode 100644 ui/effectui.cpp create mode 100644 ui/effectui.h diff --git a/dialogs/mediapropertiesdialog.cpp b/dialogs/mediapropertiesdialog.cpp index 591794cd4..8bcee21ed 100644 --- a/dialogs/mediapropertiesdialog.cpp +++ b/dialogs/mediapropertiesdialog.cpp @@ -37,175 +37,175 @@ #include "project/undo.h" MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) : - QDialog(parent), - item(i) + QDialog(parent), + item(i) { - setWindowTitle(tr("\"%1\" Properties").arg(i->get_name())); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setWindowTitle(tr("\"%1\" Properties").arg(i->get_name())); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QGridLayout* grid = new QGridLayout(this); + QGridLayout* grid = new QGridLayout(this); - int row = 0; + int row = 0; - FootagePtr f = item->to_footage(); + Footage* f = item->to_footage(); - grid->addWidget(new QLabel(tr("Tracks:"), this), row, 0, 1, 2); - row++; + grid->addWidget(new QLabel(tr("Tracks:"), this), row, 0, 1, 2); + row++; - track_list = new QListWidget(this); - for (int i=0;ivideo_tracks.size();i++) { - const FootageStream& fs = f->video_tracks.at(i); + track_list = new QListWidget(this); + for (int i=0;ivideo_tracks.size();i++) { + const FootageStream& fs = f->video_tracks.at(i); - QListWidgetItem* item = new QListWidgetItem( - tr("Video %1: %2x%3 %4FPS").arg( - QString::number(fs.file_index), - QString::number(fs.video_width), - QString::number(fs.video_height), - QString::number(fs.video_frame_rate) - ), - track_list - ); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked); - item->setData(Qt::UserRole+1, fs.file_index); - track_list->addItem(item); - } - for (int i=0;iaudio_tracks.size();i++) { - const FootageStream& fs = f->audio_tracks.at(i); - QListWidgetItem* item = new QListWidgetItem( - tr("Audio %1: %2Hz %3").arg( - QString::number(fs.file_index), - QString::number(fs.audio_frequency), - tr("%n channel(s)", "", fs.audio_channels) - ), - track_list - ); - item->setFlags(item->flags() | Qt::ItemIsUserCheckable); - item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked); - item->setData(Qt::UserRole+1, fs.file_index); - track_list->addItem(item); - } - grid->addWidget(track_list, row, 0, 1, 2); - row++; + QListWidgetItem* item = new QListWidgetItem( + tr("Video %1: %2x%3 %4FPS").arg( + QString::number(fs.file_index), + QString::number(fs.video_width), + QString::number(fs.video_height), + QString::number(fs.video_frame_rate) + ), + track_list + ); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked); + item->setData(Qt::UserRole+1, fs.file_index); + track_list->addItem(item); + } + for (int i=0;iaudio_tracks.size();i++) { + const FootageStream& fs = f->audio_tracks.at(i); + QListWidgetItem* item = new QListWidgetItem( + tr("Audio %1: %2Hz %3").arg( + QString::number(fs.file_index), + QString::number(fs.audio_frequency), + tr("%n channel(s)", "", fs.audio_channels) + ), + track_list + ); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(fs.enabled ? Qt::Checked : Qt::Unchecked); + item->setData(Qt::UserRole+1, fs.file_index); + track_list->addItem(item); + } + grid->addWidget(track_list, row, 0, 1, 2); + row++; - if (f->video_tracks.size() > 0) { - // frame conforming - if (!f->video_tracks.at(0).infinite_length) { - grid->addWidget(new QLabel(tr("Conform to Frame Rate:"), this), row, 0); - conform_fr = new QDoubleSpinBox(this); - conform_fr->setMinimum(0.01); - conform_fr->setValue(f->video_tracks.at(0).video_frame_rate * f->speed); - grid->addWidget(conform_fr, row, 1); - } + if (f->video_tracks.size() > 0) { + // frame conforming + if (!f->video_tracks.at(0).infinite_length) { + grid->addWidget(new QLabel(tr("Conform to Frame Rate:"), this), row, 0); + conform_fr = new QDoubleSpinBox(this); + conform_fr->setMinimum(0.01); + conform_fr->setValue(f->video_tracks.at(0).video_frame_rate * f->speed); + grid->addWidget(conform_fr, row, 1); + } - row++; + row++; - // premultiplied alpha mode - premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this); - premultiply_alpha_setting->setChecked(f->alpha_is_premultiplied); - grid->addWidget(premultiply_alpha_setting, row, 0); + // premultiplied alpha mode + premultiply_alpha_setting = new QCheckBox(tr("Alpha is Premultiplied"), this); + premultiply_alpha_setting->setChecked(f->alpha_is_premultiplied); + grid->addWidget(premultiply_alpha_setting, row, 0); - row++; + row++; - // deinterlacing mode - interlacing_box = new QComboBox(this); - interlacing_box->addItem( - tr("Auto (%1)").arg( - get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing) - ) - ); - interlacing_box->addItem(get_interlacing_name(VIDEO_PROGRESSIVE)); - interlacing_box->addItem(get_interlacing_name(VIDEO_TOP_FIELD_FIRST)); - interlacing_box->addItem(get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST)); + // deinterlacing mode + interlacing_box = new QComboBox(this); + interlacing_box->addItem( + tr("Auto (%1)").arg( + get_interlacing_name(f->video_tracks.at(0).video_auto_interlacing) + ) + ); + interlacing_box->addItem(get_interlacing_name(VIDEO_PROGRESSIVE)); + interlacing_box->addItem(get_interlacing_name(VIDEO_TOP_FIELD_FIRST)); + interlacing_box->addItem(get_interlacing_name(VIDEO_BOTTOM_FIELD_FIRST)); - interlacing_box->setCurrentIndex( - (f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing) - ? 0 - : f->video_tracks.at(0).video_interlacing + 1); + interlacing_box->setCurrentIndex( + (f->video_tracks.at(0).video_auto_interlacing == f->video_tracks.at(0).video_interlacing) + ? 0 + : f->video_tracks.at(0).video_interlacing + 1); - grid->addWidget(new QLabel(tr("Interlacing:"), this), row, 0); - grid->addWidget(interlacing_box, row, 1); + grid->addWidget(new QLabel(tr("Interlacing:"), this), row, 0); + grid->addWidget(interlacing_box, row, 1); - row++; - } + row++; + } - name_box = new QLineEdit(item->get_name(), this); - grid->addWidget(new QLabel(tr("Name:"), this), row, 0); - grid->addWidget(name_box, row, 1); - row++; + name_box = new QLineEdit(item->get_name(), this); + grid->addWidget(new QLabel(tr("Name:"), this), row, 0); + grid->addWidget(name_box, row, 1); + row++; - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - buttons->setCenterButtons(true); - grid->addWidget(buttons, row, 0, 1, 2); + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + buttons->setCenterButtons(true); + grid->addWidget(buttons, row, 0, 1, 2); - connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); } void MediaPropertiesDialog::accept() { - FootagePtr f = item->to_footage(); + Footage* f = item->to_footage(); - ComboAction* ca = new ComboAction(); + ComboAction* ca = new ComboAction(); - // set track enable - for (int i=0;icount();i++) { - QListWidgetItem* item = track_list->item(i); - const QVariant& data = item->data(Qt::UserRole+1); - if (!data.isNull()) { - int index = data.toInt(); - bool found = false; - for (int j=0;jvideo_tracks.size();j++) { - if (f->video_tracks.at(j).file_index == index) { - f->video_tracks[j].enabled = (item->checkState() == Qt::Checked); - found = true; - break; - } - } - if (!found) { - for (int j=0;jaudio_tracks.size();j++) { - if (f->audio_tracks.at(j).file_index == index) { - f->audio_tracks[j].enabled = (item->checkState() == Qt::Checked); - break; - } - } - } - } - } + // set track enable + for (int i=0;icount();i++) { + QListWidgetItem* item = track_list->item(i); + const QVariant& data = item->data(Qt::UserRole+1); + if (!data.isNull()) { + int index = data.toInt(); + bool found = false; + for (int j=0;jvideo_tracks.size();j++) { + if (f->video_tracks.at(j).file_index == index) { + f->video_tracks[j].enabled = (item->checkState() == Qt::Checked); + found = true; + break; + } + } + if (!found) { + for (int j=0;jaudio_tracks.size();j++) { + if (f->audio_tracks.at(j).file_index == index) { + f->audio_tracks[j].enabled = (item->checkState() == Qt::Checked); + break; + } + } + } + } + } - bool refresh_clips = false; + bool refresh_clips = false; - // set interlacing - if (f->video_tracks.size() > 0) { - if (interlacing_box->currentIndex() > 0) { - ca->append(new SetInt(&f->video_tracks[0].video_interlacing, interlacing_box->currentIndex() - 1)); - } else { - ca->append(new SetInt(&f->video_tracks[0].video_interlacing, f->video_tracks.at(0).video_auto_interlacing)); - } + // set interlacing + if (f->video_tracks.size() > 0) { + if (interlacing_box->currentIndex() > 0) { + ca->append(new SetInt(&f->video_tracks[0].video_interlacing, interlacing_box->currentIndex() - 1)); + } else { + ca->append(new SetInt(&f->video_tracks[0].video_interlacing, f->video_tracks.at(0).video_auto_interlacing)); + } - // set frame rate conform - if (!f->video_tracks.at(0).infinite_length) { - if (!qFuzzyCompare(conform_fr->value(), f->video_tracks.at(0).video_frame_rate)) { - ca->append(new SetDouble(&f->speed, f->speed, conform_fr->value()/f->video_tracks.at(0).video_frame_rate)); - refresh_clips = true; - } - } + // set frame rate conform + if (!f->video_tracks.at(0).infinite_length) { + if (!qFuzzyCompare(conform_fr->value(), f->video_tracks.at(0).video_frame_rate)) { + ca->append(new SetDouble(&f->speed, f->speed, conform_fr->value()/f->video_tracks.at(0).video_frame_rate)); + refresh_clips = true; + } + } - // set premultiplied alpha - f->alpha_is_premultiplied = premultiply_alpha_setting->isChecked(); - } + // set premultiplied alpha + f->alpha_is_premultiplied = premultiply_alpha_setting->isChecked(); + } - // set name - MediaRename* mr = new MediaRename(item, name_box->text()); + // set name + MediaRename* mr = new MediaRename(item, name_box->text()); - ca->append(mr); - ca->appendPost(new CloseAllClipsCommand()); - ca->appendPost(new UpdateFootageTooltip(item)); - if (refresh_clips) { - ca->appendPost(new RefreshClips(item)); - } - ca->appendPost(new UpdateViewer()); + ca->append(mr); + ca->appendPost(new CloseAllClipsCommand()); + ca->appendPost(new UpdateFootageTooltip(item)); + if (refresh_clips) { + ca->appendPost(new RefreshClips(item)); + } + ca->appendPost(new UpdateViewer()); - olive::UndoStack.push(ca); + olive::UndoStack.push(ca); - QDialog::accept(); + QDialog::accept(); } diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 0186b6ce0..b4b6e05a5 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -40,245 +40,245 @@ #include extern "C" { - #include +#include } NewSequenceDialog::NewSequenceDialog(QWidget *parent, Media *existing) : - QDialog(parent), - existing_item(existing) + QDialog(parent), + existing_item(existing) { - setup_ui(); + setup_ui(); - if (existing != nullptr) { - existing_sequence = existing->to_sequence(); - setWindowTitle(tr("Editing \"%1\"").arg(existing_sequence->name)); + if (existing != nullptr) { + existing_sequence = existing->to_sequence(); + setWindowTitle(tr("Editing \"%1\"").arg(existing_sequence->name)); - width_numeric->setValue(existing_sequence->width); - height_numeric->setValue(existing_sequence->height); - int comp_rate = qRound(existing_sequence->frame_rate*100); - for (int i=0;icount();i++) { - if (qRound(frame_rate_combobox->itemData(i).toDouble()*100) == comp_rate) { - frame_rate_combobox->setCurrentIndex(i); - break; - } - } - sequence_name_edit->setText(existing_sequence->name); - for (int i=0;icount();i++) { - if (audio_frequency_combobox->itemData(i) == existing_sequence->audio_frequency) { - audio_frequency_combobox->setCurrentIndex(i); - break; - } - } - } else { - existing_sequence = nullptr; - setWindowTitle(tr("New Sequence")); - } + width_numeric->setValue(existing_sequence->width); + height_numeric->setValue(existing_sequence->height); + int comp_rate = qRound(existing_sequence->frame_rate*100); + for (int i=0;icount();i++) { + if (qRound(frame_rate_combobox->itemData(i).toDouble()*100) == comp_rate) { + frame_rate_combobox->setCurrentIndex(i); + break; + } + } + sequence_name_edit->setText(existing_sequence->name); + for (int i=0;icount();i++) { + if (audio_frequency_combobox->itemData(i) == existing_sequence->audio_frequency) { + audio_frequency_combobox->setCurrentIndex(i); + break; + } + } + } else { + existing_sequence = nullptr; + setWindowTitle(tr("New Sequence")); + } } NewSequenceDialog::~NewSequenceDialog() {} void NewSequenceDialog::set_sequence_name(const QString& s) { - sequence_name_edit->setText(s); + sequence_name_edit->setText(s); } void NewSequenceDialog::create() { - if (existing_sequence == nullptr) { - SequencePtr s(new Sequence()); + if (existing_sequence == nullptr) { + SequencePtr s = std::make_shared(); - s->name = sequence_name_edit->text(); - s->width = width_numeric->value(); - s->height = height_numeric->value(); - s->frame_rate = frame_rate_combobox->currentData().toDouble(); - s->audio_frequency = audio_frequency_combobox->currentData().toInt(); - s->audio_layout = AV_CH_LAYOUT_STEREO; + s->name = sequence_name_edit->text(); + s->width = width_numeric->value(); + s->height = height_numeric->value(); + s->frame_rate = frame_rate_combobox->currentData().toDouble(); + s->audio_frequency = audio_frequency_combobox->currentData().toInt(); + s->audio_layout = AV_CH_LAYOUT_STEREO; - ComboAction* ca = new ComboAction(); - panel_project->create_sequence_internal(ca, s, true, nullptr); - olive::UndoStack.push(ca); - } else { - ComboAction* ca = new ComboAction(); + ComboAction* ca = new ComboAction(); + panel_project->create_sequence_internal(ca, s, true, nullptr); + olive::UndoStack.push(ca); + } else { + ComboAction* ca = new ComboAction(); - double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate; + double multiplier = frame_rate_combobox->currentData().toDouble() / existing_sequence->frame_rate; - EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_sequence); - esc->name = sequence_name_edit->text(); - esc->width = width_numeric->value(); - esc->height = height_numeric->value(); - esc->frame_rate = frame_rate_combobox->currentData().toDouble(); - esc->audio_frequency = audio_frequency_combobox->currentData().toInt(); - esc->audio_layout = AV_CH_LAYOUT_STEREO; - ca->append(esc); + EditSequenceCommand* esc = new EditSequenceCommand(existing_item, existing_sequence); + esc->name = sequence_name_edit->text(); + esc->width = width_numeric->value(); + esc->height = height_numeric->value(); + esc->frame_rate = frame_rate_combobox->currentData().toDouble(); + esc->audio_frequency = audio_frequency_combobox->currentData().toInt(); + esc->audio_layout = AV_CH_LAYOUT_STEREO; + ca->append(esc); - for (int i=0;iclips.size();i++) { - ClipPtr c = existing_sequence->clips.at(i); - if (c != nullptr) { - c->refactor_frame_rate(ca, multiplier, true); - } - } + for (int i=0;iclips.size();i++) { + ClipPtr c = existing_sequence->clips.at(i); + if (c != nullptr) { + c->refactor_frame_rate(ca, multiplier, true); + } + } - olive::UndoStack.push(ca); - } + olive::UndoStack.push(ca); + } - accept(); + accept(); } void NewSequenceDialog::preset_changed(int index) { - switch (index) { - case 0: // FILM 4K - width_numeric->setValue(4096); - height_numeric->setValue(2160); - break; - case 1: // TV 4K - width_numeric->setValue(3840); - height_numeric->setValue(2160); - break; - case 2: // 1080p - width_numeric->setValue(1920); - height_numeric->setValue(1080); - break; - case 3: // 720p - width_numeric->setValue(1280); - height_numeric->setValue(720); - break; - case 4: // 480p - width_numeric->setValue(640); - height_numeric->setValue(480); - break; - case 5: // 360p - width_numeric->setValue(640); - height_numeric->setValue(360); - break; - case 6: // 240p - width_numeric->setValue(320); - height_numeric->setValue(240); - break; - case 7: // 144p - width_numeric->setValue(192); - height_numeric->setValue(144); - break; - case 8: // NTSC (480i) - width_numeric->setValue(720); - height_numeric->setValue(480); - break; - case 9: // PAL (576i) - width_numeric->setValue(720); - height_numeric->setValue(576); - break; - } + switch (index) { + case 0: // FILM 4K + width_numeric->setValue(4096); + height_numeric->setValue(2160); + break; + case 1: // TV 4K + width_numeric->setValue(3840); + height_numeric->setValue(2160); + break; + case 2: // 1080p + width_numeric->setValue(1920); + height_numeric->setValue(1080); + break; + case 3: // 720p + width_numeric->setValue(1280); + height_numeric->setValue(720); + break; + case 4: // 480p + width_numeric->setValue(640); + height_numeric->setValue(480); + break; + case 5: // 360p + width_numeric->setValue(640); + height_numeric->setValue(360); + break; + case 6: // 240p + width_numeric->setValue(320); + height_numeric->setValue(240); + break; + case 7: // 144p + width_numeric->setValue(192); + height_numeric->setValue(144); + break; + case 8: // NTSC (480i) + width_numeric->setValue(720); + height_numeric->setValue(480); + break; + case 9: // PAL (576i) + width_numeric->setValue(720); + height_numeric->setValue(576); + break; + } } void NewSequenceDialog::setup_ui() { - QVBoxLayout* verticalLayout = new QVBoxLayout(this); + QVBoxLayout* verticalLayout = new QVBoxLayout(this); - QWidget* widget = new QWidget(this); + QWidget* widget = new QWidget(this); - QHBoxLayout* preset_layout = new QHBoxLayout(widget); - preset_layout->setContentsMargins(0, 0, 0, 0); + QHBoxLayout* preset_layout = new QHBoxLayout(widget); + preset_layout->setContentsMargins(0, 0, 0, 0); - preset_layout->addWidget(new QLabel(tr("Preset:"), this)); + preset_layout->addWidget(new QLabel(tr("Preset:"), this)); - preset_combobox = new QComboBox(widget); + preset_combobox = new QComboBox(widget); - preset_combobox->addItem(tr("Film 4K")); - preset_combobox->addItem(tr("TV 4K (Ultra HD/2160p)")); - preset_combobox->addItem(tr("1080p")); - preset_combobox->addItem(tr("720p")); - preset_combobox->addItem(tr("480p")); - preset_combobox->addItem(tr("360p")); - preset_combobox->addItem(tr("240p")); - preset_combobox->addItem(tr("144p")); - preset_combobox->addItem(tr("NTSC (480i)")); - preset_combobox->addItem(tr("PAL (576i)")); - preset_combobox->addItem(tr("Custom")); - preset_combobox->setCurrentIndex(2); + preset_combobox->addItem(tr("Film 4K")); + preset_combobox->addItem(tr("TV 4K (Ultra HD/2160p)")); + preset_combobox->addItem(tr("1080p")); + preset_combobox->addItem(tr("720p")); + preset_combobox->addItem(tr("480p")); + preset_combobox->addItem(tr("360p")); + preset_combobox->addItem(tr("240p")); + preset_combobox->addItem(tr("144p")); + preset_combobox->addItem(tr("NTSC (480i)")); + preset_combobox->addItem(tr("PAL (576i)")); + preset_combobox->addItem(tr("Custom")); + preset_combobox->setCurrentIndex(2); - preset_layout->addWidget(preset_combobox); + preset_layout->addWidget(preset_combobox); - verticalLayout->addWidget(widget); + verticalLayout->addWidget(widget); - QGroupBox* videoGroupBox = new QGroupBox(this); - videoGroupBox->setTitle(tr("Video")); + QGroupBox* videoGroupBox = new QGroupBox(this); + videoGroupBox->setTitle(tr("Video")); - QGridLayout* videoLayout = new QGridLayout(videoGroupBox); + QGridLayout* videoLayout = new QGridLayout(videoGroupBox); - videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1); - width_numeric = new QSpinBox(videoGroupBox); - width_numeric->setMaximum(9999); - width_numeric->setValue(1920); - videoLayout->addWidget(width_numeric, 0, 2, 1, 2); + videoLayout->addWidget(new QLabel(tr("Width:"), this), 0, 0, 1, 1); + width_numeric = new QSpinBox(videoGroupBox); + width_numeric->setMaximum(9999); + width_numeric->setValue(1920); + videoLayout->addWidget(width_numeric, 0, 2, 1, 2); - videoLayout->addWidget(new QLabel(tr("Height:"), this), 1, 0, 1, 2); - height_numeric = new QSpinBox(videoGroupBox); - height_numeric->setMaximum(9999); - height_numeric->setValue(1080); - videoLayout->addWidget(height_numeric, 1, 2, 1, 2); + videoLayout->addWidget(new QLabel(tr("Height:"), this), 1, 0, 1, 2); + height_numeric = new QSpinBox(videoGroupBox); + height_numeric->setMaximum(9999); + height_numeric->setValue(1080); + videoLayout->addWidget(height_numeric, 1, 2, 1, 2); - videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1); - frame_rate_combobox = new QComboBox(videoGroupBox); - frame_rate_combobox->addItem("10 FPS", 10.0); - frame_rate_combobox->addItem("12.5 FPS", 12.5); - frame_rate_combobox->addItem("15 FPS", 15.0); - frame_rate_combobox->addItem("23.976 FPS", 23.976); - frame_rate_combobox->addItem("24 FPS", 24.0); - frame_rate_combobox->addItem("25 FPS", 25.0); - frame_rate_combobox->addItem("29.97 FPS", 29.97); - frame_rate_combobox->addItem("30 FPS", 30.0); - frame_rate_combobox->addItem("50 FPS", 50.0); - frame_rate_combobox->addItem("59.94 FPS", 59.94); - frame_rate_combobox->addItem("60 FPS", 60.0); - frame_rate_combobox->setCurrentIndex(6); - videoLayout->addWidget(frame_rate_combobox, 2, 2, 1, 2); + videoLayout->addWidget(new QLabel(tr("Frame Rate:"), this), 2, 0, 1, 1); + frame_rate_combobox = new QComboBox(videoGroupBox); + frame_rate_combobox->addItem("10 FPS", 10.0); + frame_rate_combobox->addItem("12.5 FPS", 12.5); + frame_rate_combobox->addItem("15 FPS", 15.0); + frame_rate_combobox->addItem("23.976 FPS", 23.976); + frame_rate_combobox->addItem("24 FPS", 24.0); + frame_rate_combobox->addItem("25 FPS", 25.0); + frame_rate_combobox->addItem("29.97 FPS", 29.97); + frame_rate_combobox->addItem("30 FPS", 30.0); + frame_rate_combobox->addItem("50 FPS", 50.0); + frame_rate_combobox->addItem("59.94 FPS", 59.94); + frame_rate_combobox->addItem("60 FPS", 60.0); + frame_rate_combobox->setCurrentIndex(6); + videoLayout->addWidget(frame_rate_combobox, 2, 2, 1, 2); - videoLayout->addWidget(new QLabel(tr("Pixel Aspect Ratio:"), this), 4, 0, 1, 1); - par_combobox = new QComboBox(videoGroupBox); - par_combobox->addItem(tr("Square Pixels (1.0)")); - videoLayout->addWidget(par_combobox, 4, 2, 1, 2); + videoLayout->addWidget(new QLabel(tr("Pixel Aspect Ratio:"), this), 4, 0, 1, 1); + par_combobox = new QComboBox(videoGroupBox); + par_combobox->addItem(tr("Square Pixels (1.0)")); + videoLayout->addWidget(par_combobox, 4, 2, 1, 2); - videoLayout->addWidget(new QLabel(tr("Interlacing:"), this), 6, 0, 1, 1); - interlacing_combobox = new QComboBox(videoGroupBox); - interlacing_combobox->addItem(tr("None (Progressive)")); -// interlacing_combobox->addItem("Upper Field First"); -// interlacing_combobox->addItem("Lower Field First"); - videoLayout->addWidget(interlacing_combobox, 6, 2, 1, 2); + videoLayout->addWidget(new QLabel(tr("Interlacing:"), this), 6, 0, 1, 1); + interlacing_combobox = new QComboBox(videoGroupBox); + interlacing_combobox->addItem(tr("None (Progressive)")); + // interlacing_combobox->addItem("Upper Field First"); + // interlacing_combobox->addItem("Lower Field First"); + videoLayout->addWidget(interlacing_combobox, 6, 2, 1, 2); - verticalLayout->addWidget(videoGroupBox); + verticalLayout->addWidget(videoGroupBox); - QGroupBox* audioGroupBox = new QGroupBox(this); - audioGroupBox->setTitle(tr("Audio")); + QGroupBox* audioGroupBox = new QGroupBox(this); + audioGroupBox->setTitle(tr("Audio")); - QGridLayout* audioLayout = new QGridLayout(audioGroupBox); + QGridLayout* audioLayout = new QGridLayout(audioGroupBox); - audioLayout->addWidget(new QLabel(tr("Sample Rate: "), this), 0, 0, 1, 1); + audioLayout->addWidget(new QLabel(tr("Sample Rate: "), this), 0, 0, 1, 1); - audio_frequency_combobox = new QComboBox(audioGroupBox); - combobox_audio_sample_rates(audio_frequency_combobox); - audio_frequency_combobox->setCurrentIndex(4); + audio_frequency_combobox = new QComboBox(audioGroupBox); + combobox_audio_sample_rates(audio_frequency_combobox); + audio_frequency_combobox->setCurrentIndex(4); - audioLayout->addWidget(audio_frequency_combobox, 0, 1, 1, 1); + audioLayout->addWidget(audio_frequency_combobox, 0, 1, 1, 1); - verticalLayout->addWidget(audioGroupBox); + verticalLayout->addWidget(audioGroupBox); - QWidget* nameWidget = new QWidget(this); - QHBoxLayout* nameLayout = new QHBoxLayout(nameWidget); - nameLayout->setContentsMargins(0, 0, 0, 0); + QWidget* nameWidget = new QWidget(this); + QHBoxLayout* nameLayout = new QHBoxLayout(nameWidget); + nameLayout->setContentsMargins(0, 0, 0, 0); - nameLayout->addWidget(new QLabel(tr("Name:"), this)); + nameLayout->addWidget(new QLabel(tr("Name:"), this)); - sequence_name_edit = new QLineEdit(nameWidget); + sequence_name_edit = new QLineEdit(nameWidget); - nameLayout->addWidget(sequence_name_edit); + nameLayout->addWidget(sequence_name_edit); - verticalLayout->addWidget(nameWidget); + verticalLayout->addWidget(nameWidget); - QDialogButtonBox* buttonBox = new QDialogButtonBox(this); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - buttonBox->setCenterButtons(true); + QDialogButtonBox* buttonBox = new QDialogButtonBox(this); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + buttonBox->setCenterButtons(true); - verticalLayout->addWidget(buttonBox); + verticalLayout->addWidget(buttonBox); - connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(preset_changed(int))); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(create())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(preset_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(preset_changed(int))); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(create())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h index 8638b0e99..b77fa0852 100644 --- a/dialogs/newsequencedialog.h +++ b/dialogs/newsequencedialog.h @@ -32,32 +32,32 @@ class NewSequenceDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr); - ~NewSequenceDialog(); + explicit NewSequenceDialog(QWidget *parent = nullptr, Media* existing = nullptr); + ~NewSequenceDialog(); - void set_sequence_name(const QString& s); + void set_sequence_name(const QString& s); private slots: - void create(); - void preset_changed(int index); + void create(); + void preset_changed(int index); private: - SequencePtr existing_sequence; - Media* existing_item; + Sequence* existing_sequence; + Media* existing_item; - void setup_ui(); + void setup_ui(); - QComboBox* preset_combobox; - QSpinBox* height_numeric; - QSpinBox* width_numeric; - QComboBox* par_combobox; - QComboBox* interlacing_combobox; - QComboBox* frame_rate_combobox; - QComboBox* audio_frequency_combobox; - QLineEdit* sequence_name_edit; + QComboBox* preset_combobox; + QSpinBox* height_numeric; + QSpinBox* width_numeric; + QComboBox* par_combobox; + QComboBox* interlacing_combobox; + QComboBox* frame_rate_combobox; + QComboBox* audio_frequency_combobox; + QLineEdit* sequence_name_edit; }; #endif // NEWSEQUENCEDIALOG_H diff --git a/dialogs/proxydialog.cpp b/dialogs/proxydialog.cpp index 9043c9f1e..fb2641de1 100644 --- a/dialogs/proxydialog.cpp +++ b/dialogs/proxydialog.cpp @@ -103,7 +103,7 @@ void ProxyDialog::accept() { info.codec_type = 0; info.size_multiplier = size_combobox->currentData().toDouble(); - FootagePtr footage = selected_media.at(i)->to_footage(); + Footage* footage = selected_media.at(i)->to_footage(); QString base_footage_fn = QFileInfo(footage->url).baseName(); @@ -148,7 +148,7 @@ void ProxyDialog::accept() { // all proxy info checks out, queue it with the proxy generator for (int i=0;ito_footage(); + Footage* footage = info_list.at(i).media->to_footage(); footage->proxy = true; footage->proxy_path.clear(); diff --git a/effects/internal/voideffect.cpp b/effects/internal/voideffect.cpp index 49c71eff8..d68f2ddbe 100644 --- a/effects/internal/voideffect.cpp +++ b/effects/internal/voideffect.cpp @@ -28,7 +28,6 @@ #include "debug.h" VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) { - name = n; QString display_name; if (n.isEmpty()) { display_name = tr("(unknown)"); @@ -39,15 +38,15 @@ VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) { new LabelField(row, display_name); - container->setText(display_name); + name = display_name; void_meta.type = EFFECT_TYPE_EFFECT; meta = &void_meta; } EffectPtr VoidEffect::copy(Clip* c) { - EffectPtr copy(new VoidEffect(c, name)); - copy->set_enabled(is_enabled()); + EffectPtr copy = std::make_shared(c, name); + copy->SetEnabled(IsEnabled()); copy_field_keyframes(copy); return copy; } @@ -55,31 +54,31 @@ EffectPtr VoidEffect::copy(Clip* c) { void VoidEffect::load(QXmlStreamReader &stream) { QString tag = stream.name().toString(); - QXmlStreamWriter writer(&bytes); + QXmlStreamWriter writer(&bytes); - // copy XML from reader to writer - while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { + // copy XML from reader to writer + while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { stream.readNext(); - if (stream.isStartElement()) { - writer.writeStartElement(stream.name().toString()); - } - if (stream.isEndElement()) { - writer.writeEndElement(); - } - if (stream.isCharacters()) { - writer.writeCharacters(stream.text().toString()); - } - for (int i=0;i tag, ignored when loading stream.writeStartElement("void"); diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 6b2dc103b..fa23eb733 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -372,7 +372,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } else if (attr.name() == "alayout") { s->audio_layout = attr.value().toInt(); } else if (attr.name() == "open") { - open_seq = s; + open_seq = s.get(); } else if (attr.name() == "workarea") { s->using_workarea = (attr.value() == "1"); } else if (attr.name() == "workareaIn") { @@ -400,7 +400,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { int media_type = -1; int media_id, stream_id; - ClipPtr c = std::make_shared(s); + ClipPtr c = std::make_shared(s.get()); QColor clip_color; ClipSpeed speed_info = c->speed(); @@ -457,7 +457,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { case MEDIA_TYPE_FOOTAGE: if (media_id >= 0) { for (int j=0;jto_footage(); + Footage* m = loaded_media_items.at(j)->to_footage(); if (m->save_id == media_id) { c->set_media(loaded_media_items.at(j), stream_id); break; @@ -784,12 +784,12 @@ void LoadThread::create_effect_ui( if (meta == nullptr) { // create void effect EffectPtr ve(new VoidEffect(c, *effect_name)); - ve->set_enabled(effect_enabled); + ve->SetEnabled(effect_enabled); ve->load(*stream); c->effects.append(ve); } else { EffectPtr e(Effect::Create(c, meta)); - e->set_enabled(effect_enabled); + e->SetEnabled(effect_enabled); e->load(*stream); c->effects.append(e); @@ -797,7 +797,7 @@ void LoadThread::create_effect_ui( } else { TransitionPtr t = Transition::Create(c, nullptr, meta); if (effect_length > -1) t->set_length(effect_length); - t->set_enabled(effect_enabled); + t->SetEnabled(effect_enabled); t->load(*stream); if (type == kTransitionOpening) { diff --git a/io/loadthread.h b/io/loadthread.h index 14b92e7b2..2ecd4a593 100644 --- a/io/loadthread.h +++ b/io/loadthread.h @@ -72,7 +72,7 @@ private: void read_next_start_element(QXmlStreamReader& stream); void update_current_element_count(QXmlStreamReader& stream); - SequencePtr open_seq; + Sequence* open_seq; QVector loaded_media_items; QDir proj_dir; QDir internal_proj_dir; diff --git a/io/previewgenerator.h b/io/previewgenerator.h index 8abd5f0e4..8b273be64 100644 --- a/io/previewgenerator.h +++ b/io/previewgenerator.h @@ -55,7 +55,7 @@ private: AVFormatContext* fmt_ctx_; Media* media_; - FootagePtr footage_; + Footage* footage_; bool retrieve_duration_; bool contains_still_image_; bool cancelled_; diff --git a/io/proxygenerator.cpp b/io/proxygenerator.cpp index 9bba533a2..cb37a5a0a 100644 --- a/io/proxygenerator.cpp +++ b/io/proxygenerator.cpp @@ -42,7 +42,7 @@ enum AVCodecID temp_enc_codec = AV_CODEC_ID_PRORES; ProxyGenerator::ProxyGenerator() : cancelled(false) {} void ProxyGenerator::transcode(const ProxyInfo& info) { - FootagePtr footage = info.media->to_footage(); + Footage* footage = info.media->to_footage(); // set progress to 0 current_progress = 0.0; diff --git a/mainwindow.cpp b/mainwindow.cpp index 2ed4ea568..ad4d885c2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -939,7 +939,7 @@ void MainWindow::closeEvent(QCloseEvent *e) { // stop proxy generator thread olive::proxy_generator.cancel(); - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); olive::Global->set_sequence(nullptr); diff --git a/olive.pro b/olive.pro index 87d239992..baa966ea2 100644 --- a/olive.pro +++ b/olive.pro @@ -170,7 +170,8 @@ SOURCES += \ project/effectfields/combofield.cpp \ project/effectfields/filefield.cpp \ project/effectfields/labelfield.cpp \ - project/effectfields/buttonfield.cpp + project/effectfields/buttonfield.cpp \ + ui/effectui.cpp HEADERS += \ mainwindow.h \ @@ -294,7 +295,8 @@ HEADERS += \ project/effectfields/combofield.h \ project/effectfields/filefield.h \ project/effectfields/labelfield.h \ - project/effectfields/buttonfield.h + project/effectfields/buttonfield.h \ + ui/effectui.h FORMS += diff --git a/oliveglobal.cpp b/oliveglobal.cpp index 35b9f3d01..b293f79e0 100644 --- a/oliveglobal.cpp +++ b/oliveglobal.cpp @@ -147,7 +147,7 @@ void OliveGlobal::load_translation_from_config() { void OliveGlobal::new_project() { if (can_close_project()) { // clear effects panel - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); // clear project contents (footage, sequences, etc.) panel_project->new_project(); @@ -286,9 +286,9 @@ void OliveGlobal::open_preferences() { pd.exec(); } -void OliveGlobal::set_sequence(SequencePtr s) +void OliveGlobal::set_sequence(Sequence* s) { - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); olive::ActiveSequence = s; panel_sequence_viewer->set_main_sequence(); diff --git a/oliveglobal.h b/oliveglobal.h index 305beefb8..2cfd348f8 100644 --- a/oliveglobal.h +++ b/oliveglobal.h @@ -274,7 +274,7 @@ public slots: * * The Sequence to set as the active Sequence. */ - void set_sequence(SequencePtr s); + void set_sequence(Sequence *s); private: /** diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 174baa795..ab155daea 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -44,6 +44,7 @@ #include "panels/viewer.h" #include "panels/grapheditor.h" #include "ui/viewerwidget.h" +#include "ui/menuhelper.h" #include "io/clipboard.h" #include "io/config.h" #include "ui/timelineheader.h" @@ -53,14 +54,14 @@ EffectControls::EffectControls(QWidget *parent) : Panel(parent), - multiple(false), zoom(1), - mode(kTransitionNone) + mode_(kTransitionNone) { setup_ui(); Retranslate(); - clear_effects(false); + Clear(false); + headers->viewer = panel_sequence_viewer; headers->snapping = false; @@ -69,8 +70,6 @@ EffectControls::EffectControls(QWidget *parent) : effects_area->header = headers; keyframeView->header = headers; - lblMultipleClipsSelected->setVisible(false); - connect(keyframeView, SIGNAL(wheel_event_signal(QWheelEvent*)), effects_area, SLOT(receive_wheel_event(QWheelEvent*))); connect(horizontalScrollBar, SIGNAL(valueChanged(int)), headers, SLOT(set_scroll(int))); connect(horizontalScrollBar, SIGNAL(resize_move(double)), keyframeView, SLOT(resize_move(double))); @@ -80,10 +79,9 @@ EffectControls::EffectControls(QWidget *parent) : connect(scrollArea->verticalScrollBar(), SIGNAL(valueChanged(int)), verticalScrollBar, SLOT(setValue(int))); } -EffectControls::~EffectControls() {} - -int EffectControls::get_mode() { - return mode; +EffectControls::~EffectControls() +{ + Clear(true); } bool EffectControls::keyframe_focus() { @@ -98,8 +96,8 @@ void EffectControls::set_zoom(bool in) { void EffectControls::menu_select(QAction* q) { ComboAction* ca = new ComboAction(); - for (int i=0;iclips.at(selected_clips.at(i)).get(); + for (int i=0;itrack() < 0) == (effect_menu_subtype == EFFECT_TYPE_VIDEO)) { const EffectMeta* meta = reinterpret_cast(q->data().value()); if (effect_menu_type == EFFECT_TYPE_TRANSITION) { @@ -126,7 +124,7 @@ void EffectControls::menu_select(QAction* q) { if (effect_menu_type == EFFECT_TYPE_TRANSITION) { update_ui(true); } else { - reload_clips(); + Reload(); panel_sequence_viewer->viewer_widget->frame_update(); } } @@ -141,39 +139,39 @@ void EffectControls::delete_selected_keyframes() { } void EffectControls::copy(bool del) { - if (mode == kTransitionNone) { + if (mode_ == kTransitionNone) { bool cleared = false; - ComboAction* ca = new ComboAction(); - EffectDeleteCommand* del_com = (del) ? new EffectDeleteCommand() : nullptr; - for (int i=0;iclips.at(selected_clips.at(i)).get(); - for (int j=0;jeffects.size();j++) { - EffectPtr effect = c->effects.at(j); - if (effect->container->selected) { - if (!cleared) { - clear_clipboard(); - cleared = true; - clipboard_type = CLIPBOARD_TYPE_EFFECT; - } + ComboAction* ca = nullptr; + if (del) { + ca = new ComboAction(); + } - clipboard.append(EffectPtr(effect->copy(nullptr))); + for (int i=0;iIsSelected()) { + Effect* e = open_effects_.at(i)->GetEffect(); - if (del_com != nullptr) { - del_com->clips.append(c); - del_com->fx.append(j); - } + if (!cleared) { + clear_clipboard(); + cleared = true; + clipboard_type = CLIPBOARD_TYPE_EFFECT; + } + + clipboard.append(e->copy(nullptr)); + + if (del) { + ca->append(new EffectDeleteCommand(e)); } } } - if (del_com != nullptr) { - if (del_com->clips.size() > 0) { - ca->append(del_com); + + if (del) { + if (ca->hasActions()) { + olive::UndoStack.push(ca); } else { - delete del_com; + delete ca; } } - olive::UndoStack.push(ca); } } @@ -181,11 +179,6 @@ void EffectControls::scroll_to_frame(long frame) { scroll_to_frame_internal(horizontalScrollBar, frame - keyframeView->visible_in, zoom, keyframeView->width()); } -void EffectControls::add_effect_paste_action(QMenu *menu) { - QAction* paste_action = menu->addAction(tr("&Paste"), panel_timeline, SLOT(paste(bool))); - paste_action->setEnabled(clipboard.size() > 0 && clipboard_type == CLIPBOARD_TYPE_EFFECT); -} - void EffectControls::cut() { copy(true); } @@ -260,56 +253,68 @@ void EffectControls::show_effect_menu(int type, int subtype) { effects_menu.exec(QCursor::pos()); } -void EffectControls::clear_effects(bool clear_cache) { +void EffectControls::Clear(bool clear_cache) { // clear existing clips deselect_all_effects(nullptr); // clear graph editor if (panel_graph_editor != nullptr) panel_graph_editor->set_row(nullptr); - QVBoxLayout* video_layout = static_cast(video_effect_area->layout()); - QVBoxLayout* audio_layout = static_cast(audio_effect_area->layout()); - QLayoutItem* item; - while ((item = video_layout->takeAt(0))) { - item->widget()->setParent(nullptr); - disconnect(static_cast(item->widget()), SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*))); + for (int i=0;itakeAt(0))) { - item->widget()->setParent(nullptr); - disconnect(static_cast(item->widget()), SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*))); - } - lblMultipleClipsSelected->setVisible(false); + open_effects_.clear(); + vcontainer->setVisible(false); acontainer->setVisible(false); headers->setVisible(false); keyframeView->setEnabled(false); - if (clear_cache) selected_clips.clear(); + + if (clear_cache) { + selected_clips_.clear(); + } + UpdateTitle(); } -void EffectControls::deselect_all_effects(QWidget* sender) { - for (int i=0;iclips.at(selected_clips.at(i)); - for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->container != sender) { - c->effects.at(j)->container->header_click(false, false); - } +bool EffectControls::IsEffectSelected(Effect *e) +{ + for (int i=0;iGetEffect() == e && open_effects_.at(i)->IsSelected()) { + return true; } } + return false; +} + +void EffectControls::deselect_all_effects(QWidget* sender) { + + for (int i=0;iheader_click(false, false); + } + } + panel_sequence_viewer->viewer_widget->update(); } -void EffectControls::open_effect(QVBoxLayout* layout, EffectPtr e) { - CollapsibleWidget* container = e->container; - layout->addWidget(container); +void EffectControls::open_effect(QVBoxLayout* layout, Effect* e) { + EffectUI* container = new EffectUI(e); + + connect(container, SIGNAL(CutRequested()), this, SLOT(cut())); + connect(container, SIGNAL(CopyRequested()), this, SLOT(copy(bool))); connect(container, SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*))); + + open_effects_.append(container); + + layout->addWidget(container); } void EffectControls::UpdateTitle() { - if (selected_clips.empty()) { + if (selected_clips_.isEmpty()) { setWindowTitle(panel_name + tr("(none)")); } else { - setWindowTitle(panel_name + olive::ActiveSequence->clips.at(selected_clips.at(0))->name()); + setWindowTitle(panel_name + selected_clips_.first()->name()); } } @@ -386,9 +391,9 @@ void EffectControls::setup_ui() { vcontainerLayout->addWidget(veHeader); video_effect_area = new QWidget(); - QVBoxLayout* veAreaLayout = new QVBoxLayout(video_effect_area); - veAreaLayout->setSpacing(0); - veAreaLayout->setMargin(0); + video_effect_layout = new QVBoxLayout(video_effect_area); + video_effect_layout->setSpacing(0); + video_effect_layout->setMargin(0); vcontainerLayout->addWidget(video_effect_area); @@ -428,18 +433,14 @@ void EffectControls::setup_ui() { acontainerLayout->addWidget(aeHeader); audio_effect_area = new QWidget(); - QVBoxLayout* aeAreaLayout = new QVBoxLayout(audio_effect_area); - aeAreaLayout->setSpacing(0); - aeAreaLayout->setMargin(0); + audio_effect_layout = new QVBoxLayout(audio_effect_area); + audio_effect_layout->setSpacing(0); + audio_effect_layout->setMargin(0); acontainerLayout->addWidget(audio_effect_area); effects_area_layout->addWidget(acontainer); - lblMultipleClipsSelected = new QLabel(); - lblMultipleClipsSelected->setAlignment(Qt::AlignCenter); - effects_area_layout->addWidget(lblMultipleClipsSelected); - effects_area_layout->addStretch(); scrollAreaLayout->addWidget(effects_area); @@ -501,7 +502,6 @@ void EffectControls::Retranslate() { btnAddAudioEffect->setToolTip(tr("Add Audio Effect")); lblAudioEffects->setText(tr("AUDIO EFFECTS")); btnAddAudioTransition->setToolTip(tr("Add Audio Transition")); - lblMultipleClipsSelected->setText(tr("(Multiple clips selected)")); UpdateTitle(); } @@ -529,85 +529,83 @@ void EffectControls::queue_post_update() { void EffectControls::effects_area_context_menu() { QMenu menu(this); - add_effect_paste_action(&menu); + olive::MenuHelper.create_effect_paste_action(&menu); menu.exec(QCursor::pos()); } -void EffectControls::load_effects() { - lblMultipleClipsSelected->setVisible(multiple); +void EffectControls::delete_effects() { + // load in new clips + if (mode_ == kTransitionNone) { - if (!multiple) { - // load in new clips - for (int i=0;iclips.at(selected_clips.at(i)); - QVBoxLayout* layout; - if (c->track() < 0) { - vcontainer->setVisible(true); - layout = static_cast(video_effect_area->layout()); - } else { - acontainer->setVisible(true); - layout = static_cast(audio_effect_area->layout()); - } - if (mode == kTransitionNone) { - for (int j=0;jeffects.size();j++) { - open_effect(layout, c->effects.at(j)); - } - } else if (mode == kTransitionOpening && c->opening_transition != nullptr) { - open_effect(layout, c->opening_transition); - } else if (mode == kTransitionClosing && c->closing_transition != nullptr) { - open_effect(layout, c->closing_transition); + ComboAction* ca = new ComboAction(); + + for (int i=0;iIsSelected()) { + ca->append(new EffectDeleteCommand(open_effects_.at(i)->GetEffect())); } } - if (selected_clips.size() > 0) { - keyframeView->setEnabled(true); - headers->setVisible(true); - QTimer::singleShot(50, this, SLOT(queue_post_update())); + if (ca->hasActions()) { + olive::UndoStack.push(ca); + panel_sequence_viewer->viewer_widget->frame_update(); + } else { + delete ca; } } +} + +void EffectControls::Reload() { + Clear(false); + Load(); +} + +void EffectControls::SetClips(const QVector &clips, int mode) +{ + Clear(true); + + // replace clip vector + selected_clips_ = clips; + mode_ = mode; + + Load(); +} + +void EffectControls::Load() { + // load in new clips + for (int i=0;itrack() < 0) { + vcontainer->setVisible(true); + layout = video_effect_layout; + } else { + acontainer->setVisible(true); + layout = audio_effect_layout; + } + + if (mode_ == kTransitionNone) { + for (int j=0;jeffects.size();j++) { + open_effect(layout, c->effects.at(j).get()); + } + } else if (mode_ == kTransitionOpening && c->opening_transition != nullptr) { + open_effect(layout, c->opening_transition.get()); + } else if (mode_ == kTransitionClosing && c->closing_transition != nullptr) { + open_effect(layout, c->closing_transition.get()); + } + } + if (selected_clips_.size() > 0) { + keyframeView->setEnabled(true); + headers->setVisible(true); + + QTimer::singleShot(50, this, SLOT(queue_post_update())); + } UpdateTitle(); } -void EffectControls::delete_effects() { - // load in new clips - if (mode == kTransitionNone) { - EffectDeleteCommand* command = new EffectDeleteCommand(); - for (int i=0;iclips.at(selected_clips.at(i)).get(); - for (int j=0;jeffects.size();j++) { - EffectPtr effect = c->effects.at(j); - if (effect->container->selected) { - command->clips.append(c); - command->fx.append(j); - } - } - } - if (command->clips.size() > 0) { - olive::UndoStack.push(command); - panel_sequence_viewer->viewer_widget->frame_update(); - } else { - delete command; - } - } -} - -void EffectControls::reload_clips() { - clear_effects(false); - load_effects(); -} - -void EffectControls::set_clips(QVector& clips, int m) { - clear_effects(true); - - // replace clip vector - selected_clips = clips; - mode = m; - - load_effects(); -} - void EffectControls::video_effect_click() { show_effect_menu(EFFECT_TYPE_EFFECT, EFFECT_TYPE_VIDEO); } @@ -630,18 +628,13 @@ void EffectControls::resizeEvent(QResizeEvent*) { bool EffectControls::is_focused() { if (this->hasFocus()) return true; - for (int i=0;iclips.at(selected_clips.at(i)); - if (c != nullptr) { - for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->container->is_focused()) { - return true; - } - } - } else { - qWarning() << "Tried to check focus of a nullptr clip"; + + for (int i=0;iIsFocused()) { + return true; } } + return false; } diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h index 4cc3a9116..39482789b 100644 --- a/panels/effectcontrols.h +++ b/panels/effectcontrols.h @@ -37,11 +37,12 @@ #include "ui/resizablescrollbar.h" #include "ui/keyframeview.h" #include "ui/panel.h" +#include "ui/effectui.h" class EffectsArea : public QWidget { Q_OBJECT public: - EffectsArea(QWidget* parent = 0); + EffectsArea(QWidget* parent = nullptr); QScrollArea* parent_widget; KeyframeView* keyframe_area; TimelineHeader* header; @@ -53,22 +54,23 @@ class EffectControls : public Panel { Q_OBJECT public: - explicit EffectControls(QWidget *parent = 0); - ~EffectControls(); - int get_mode(); - void set_clips(QVector& clips, int mode); - void clear_effects(bool clear_cache); + explicit EffectControls(QWidget *parent = nullptr); + virtual ~EffectControls() override; + + + void Reload(); + void SetClips(const QVector &clips, int mode); + void Clear(bool clear_cache = true); + + bool IsEffectSelected(Effect* e); + void delete_effects(); bool is_focused(); - void reload_clips(); void set_zoom(bool in); bool keyframe_focus(); void delete_selected_keyframes(); - bool multiple; void scroll_to_frame(long frame); - QVector selected_clips; - double zoom; ResizableScrollBar* horizontalScrollBar; @@ -76,8 +78,6 @@ public: QMutex effects_loaded; - void add_effect_paste_action(QMenu* menu); - virtual void Retranslate() override; virtual void LoadLayoutState(const QByteArray& data) override; @@ -103,10 +103,14 @@ private slots: protected: virtual void resizeEvent(QResizeEvent *event) override; private: + QVector selected_clips_; + QVector open_effects_; + + void Load(); + void show_effect_menu(int type, int subtype); - void load_effects(); void load_keyframes(); - void open_effect(QVBoxLayout* hlayout, EffectPtr e); + void open_effect(QVBoxLayout* hlayout, Effect *e); void UpdateTitle(); void setup_ui(); @@ -114,22 +118,24 @@ private: int effect_menu_type; int effect_menu_subtype; QString panel_name; - int mode; + int mode_; + + QWidget* video_effect_area; + QWidget* audio_effect_area; + QVBoxLayout* video_effect_layout; + QVBoxLayout* audio_effect_layout; QSplitter* splitter; QPushButton* btnAddVideoEffect; QLabel* lblVideoEffects; + QLabel* lblAudioEffects; QPushButton* btnAddVideoTransition; QPushButton* btnAddAudioEffect; QPushButton* btnAddAudioTransition; - QLabel* lblMultipleClipsSelected; - QLabel* lblAudioEffects; TimelineHeader* headers; EffectsArea* effects_area; QScrollArea* scrollArea; KeyframeView* keyframeView; - QWidget* video_effect_area; - QWidget* audio_effect_area; QWidget* vcontainer; QWidget* acontainer; }; diff --git a/panels/panels.cpp b/panels/panels.cpp index 1d87a8c2f..cdd3691ef 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -39,16 +39,11 @@ Timeline* panel_timeline = nullptr; GraphEditor* panel_graph_editor = nullptr; void update_effect_controls() { - // SEND CLIPS TO EFFECT CONTROLS - // find out how many clips are selected - // limits to one video clip and one audio clip and only if they're linked - // one of these days it might be nice to have multiple clips in the effects panel - bool multiple = false; - int vclip = -1; - int aclip = -1; - QVector selected_clips; + QVector selected_clips; int mode = kTransitionNone; + if (olive::ActiveSequence != nullptr) { + /* for (int i=0;iclips.size();i++) { Clip* clip = olive::ActiveSequence->clips.at(i).get(); if (clip != nullptr) { @@ -102,26 +97,14 @@ void update_effect_controls() { } } } + */ + + selected_clips = olive::ActiveSequence->SelectedClips(); + + // TODO handle selecting transitions } - - - bool same = (selected_clips.size() == panel_effect_controls->selected_clips.size() - && panel_effect_controls->get_mode() == mode); - if (same) { - for (int i=0;iselected_clips.at(i)) { - same = false; - break; - } - } - } - - if (panel_effect_controls->multiple != multiple || !same) { - panel_effect_controls->multiple = multiple; - - panel_effect_controls->set_clips(selected_clips, mode); - } + panel_effect_controls->SetClips(selected_clips, mode); } void update_ui(bool modified) { @@ -172,7 +155,7 @@ QDockWidget *get_focused_panel(bool force_hover) { 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_sequence_viewer->setObjectName("seq_viewer"); panel_footage_viewer = new Viewer(parent); panel_footage_viewer->setObjectName("footage_viewer"); panel_project = new Project(parent); diff --git a/panels/project.cpp b/panels/project.cpp index 1ae425d72..1806c1354 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -264,7 +264,7 @@ SequencePtr create_sequence_from_media(QVector& media_list) { switch (media->get_type()) { case MEDIA_TYPE_FOOTAGE: { - FootagePtr m = media->to_footage(); + Footage* m = media->to_footage(); if (m->ready) { if (!got_video_values) { for (int j=0;jvideo_tracks.size();j++) { @@ -292,7 +292,7 @@ SequencePtr create_sequence_from_media(QVector& media_list) { break; case MEDIA_TYPE_SEQUENCE: { - SequencePtr seq = media->to_sequence(); + Sequence* seq = media->to_sequence(); s->width = seq->width; s->height = seq->height; s->frame_rate = seq->frame_rate; @@ -440,13 +440,15 @@ Media* Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool op if (ca != nullptr) { ca->append(new NewSequenceCommand(item, parent)); - if (open) ca->append(new ChangeSequenceAction(s)); - } else { + if (open) { + ca->append(new ChangeSequenceAction(s.get())); + } + } else { olive::project_model.appendChild(parent, item); if (open) { - olive::Global->set_sequence(s); + olive::Global->set_sequence(s.get()); } } return item; @@ -530,10 +532,10 @@ void Project::delete_selected_media() { get_all_media_from_table(items, media_items, MEDIA_TYPE_FOOTAGE); for (int i=0;ito_footage(); + Footage* media = item->to_footage(); bool confirm_delete = false; for (int j=0;jto_sequence(); + Sequence* s = sequence_items.at(j)->to_sequence(); for (int k=0;kclips.size();k++) { ClipPtr c = s->clips.at(k); if (c != nullptr && c->media() == item) { @@ -600,7 +602,7 @@ void Project::delete_selected_media() { // remove if (remove) { - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); if (olive::ActiveSequence != nullptr) olive::ActiveSequence->selections.clear(); // remove media and parents @@ -619,13 +621,13 @@ void Project::delete_selected_media() { if (items.at(i)->get_type() == MEDIA_TYPE_SEQUENCE) { redraw = true; - SequencePtr s = items.at(i)->to_sequence(); + Sequence* s = items.at(i)->to_sequence(); if (s == olive::ActiveSequence) { ca->append(new ChangeSequenceAction(nullptr)); } - if (s == panel_footage_viewer->seq) { + if (s == panel_footage_viewer->seq.get()) { panel_footage_viewer->set_media(nullptr); } } else if (items.at(i)->get_type() == MEDIA_TYPE_FOOTAGE) { @@ -1009,12 +1011,11 @@ void Project::delete_clips_using_selected_media() { void Project::clear() { // clear effects cache - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); // delete sequences first because it's important to close all the clips before deleting the media QVector sequences = list_all_project_sequences(); for (int i=0;ito_sequence().reset(); sequences.at(i)->set_sequence(nullptr); } @@ -1079,7 +1080,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, } else { int folder = m->parentItem()->temp_id; if (type == MEDIA_TYPE_FOOTAGE) { - FootagePtr f = m->to_footage(); + Footage* f = m->to_footage(); f->save_id = media_id; stream.writeStartElement("footage"); stream.writeAttribute("id", QString::number(media_id)); @@ -1128,7 +1129,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, stream.writeEndElement(); // footage media_id++; } else if (type == MEDIA_TYPE_SEQUENCE) { - SequencePtr s = m->to_sequence(); + Sequence* s = m->to_sequence(); if (set_ids_only) { s->save_id = sequence_id; sequence_id++; diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 8834fa126..9de1f4154 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -177,7 +177,7 @@ void Timeline::next_cut() { } } -void ripple_clips(ComboAction* ca, SequencePtr s, long point, long length, const QVector& ignore) { +void ripple_clips(ComboAction* ca, Sequence* s, long point, long length, const QVector& ignore) { ca->append(new RippleAction(s, point, length, ignore)); } @@ -193,7 +193,7 @@ void Timeline::toggle_show_all() { } } -void Timeline::create_ghosts_from_media(SequencePtr seq, long entry_point, QVector& media_list) { +void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector& media_list) { video_ghosts = false; audio_ghosts = false; @@ -201,8 +201,8 @@ void Timeline::create_ghosts_from_media(SequencePtr seq, long entry_point, QVect bool can_import = true; Media* medium = media_list.at(i); - FootagePtr m = nullptr; - SequencePtr s = nullptr; + Footage* m = nullptr; + Sequence* s = nullptr; long sequence_length = 0; long default_clip_in = 0; long default_clip_out = 0; @@ -298,7 +298,7 @@ void Timeline::create_ghosts_from_media(SequencePtr seq, long entry_point, QVect } } -void Timeline::add_clips_from_ghosts(ComboAction* ca, SequencePtr s) { +void Timeline::add_clips_from_ghosts(ComboAction* ca, Sequence* s) { // add clips long earliest_point = LONG_MAX; QVector added_clips; @@ -314,7 +314,7 @@ void Timeline::add_clips_from_ghosts(ComboAction* ca, SequencePtr s) { c->set_clip_in(g.clip_in); c->set_track(g.track); if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - FootagePtr m = c->media()->to_footage(); + Footage* m = c->media()->to_footage(); if (m->video_tracks.size() == 0) { // audio only (greenish) c->set_color(128, 192, 128); @@ -330,7 +330,7 @@ void Timeline::add_clips_from_ghosts(ComboAction* ca, SequencePtr s) { // sequence (red?ish?) c->set_color(192, 128, 128); - SequencePtr media = c->media()->to_sequence(); + Sequence* media = c->media()->to_sequence(); c->set_name(media->name); } c->refresh(); @@ -420,7 +420,7 @@ void Timeline::nest() { ComboAction* ca = new ComboAction(); // create "nest" sequence with the same attributes as the current sequence - SequencePtr s(new Sequence()); + SequencePtr s = std::make_shared(); s->name = panel_project->get_next_sequence_name(tr("Nested Sequence")); s->width = olive::ActiveSequence->width; @@ -435,7 +435,7 @@ void Timeline::nest() { ca->append(new DeleteClipAction(olive::ActiveSequence, selected_clips.at(i))); // copy to new - ClipPtr copy(olive::ActiveSequence->clips.at(selected_clips.at(i))->copy(s)); + ClipPtr copy(olive::ActiveSequence->clips.at(selected_clips.at(i))->copy(s.get())); copy->set_timeline_in(copy->timeline_in() - earliest_point); copy->set_timeline_out(copy->timeline_out() - earliest_point); s->clips.append(copy); @@ -453,7 +453,7 @@ void Timeline::nest() { create_ghosts_from_media(olive::ActiveSequence, earliest_point, media_list); add_clips_from_ghosts(ca, olive::ActiveSequence); - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); olive::ActiveSequence->selections.clear(); olive::UndoStack.push(ca); @@ -680,7 +680,7 @@ void Timeline::toggle_enable_on_selected_clips() { void Timeline::delete_selection(QVector& selections, bool ripple_delete) { if (selections.size() > 0) { - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); ComboAction* ca = new ComboAction(); @@ -1014,7 +1014,7 @@ bool selection_contains_transition(const Selection& s, Clip* c, int type) { void Timeline::delete_areas_and_relink(ComboAction* ca, QVector& areas, bool deselect_areas) { clean_up_selections(areas); - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); QVector pre_clips; QVector post_clips; @@ -1281,10 +1281,7 @@ void Timeline::paste(bool insert) { if (found >= 0 && skip) { // do nothing } else if (found >= 0 && replace) { - EffectDeleteCommand* delcom = new EffectDeleteCommand(); - delcom->clips.append(c); - delcom->fx.append(found); - ca->append(delcom); + ca->append(new EffectDeleteCommand(c->effects.at(found).get())); ca->append(new AddEffectCommand(c, e->copy(c), nullptr, found)); } else { diff --git a/panels/timeline.h b/panels/timeline.h index 96499a088..198e23c46 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -74,7 +74,7 @@ namespace olive { int getScreenPointFromFrame(double zoom, long frame); long getFrameFromScreenPoint(double zoom, int x); bool selection_contains_transition(const Selection& s, Clip *c, int type); -void ripple_clips(ComboAction *ca, SequencePtr s, long point, long length, const QVector& ignore = QVector()); +void ripple_clips(ComboAction *ca, Sequence *s, long point, long length, const QVector& ignore = QVector()); struct Ghost { int clip; @@ -125,8 +125,8 @@ public: void edit_to_point_internal(bool in, bool ripple); void delete_in_out_internal(bool ripple); - void create_ghosts_from_media(SequencePtr seq, long entry_point, QVector &media_list); - void add_clips_from_ghosts(ComboAction *ca, SequencePtr s); + void create_ghosts_from_media(Sequence *seq, long entry_point, QVector &media_list); + void add_clips_from_ghosts(ComboAction *ca, Sequence *s); int getTimelineScreenPointFromFrame(long frame); long getTimelineFrameFromScreenPoint(int x); diff --git a/panels/viewer.cpp b/panels/viewer.cpp index c6455b347..8cf5db31a 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -449,9 +449,9 @@ void Viewer::pause() { panel_project->process_file_list(file_list); // add it to the sequence - ClipPtr c = std::make_shared(seq); + ClipPtr c = std::make_shared(seq.get()); Media* m = panel_project->last_imported_media.at(0); - FootagePtr f = m->to_footage(); + Footage* f = m->to_footage(); // wait for footage to be completely ready before taking metadata from it f->ready_lock.lock(); @@ -468,7 +468,7 @@ void Viewer::pause() { QVector add_clips; add_clips.append(c); - olive::UndoStack.push(new AddClipCommand(seq, add_clips)); // add clip + olive::UndoStack.push(new AddClipCommand(seq.get(), add_clips)); // add clip } } } @@ -514,7 +514,7 @@ int Viewer::get_playback_speed() { } void Viewer::set_marker() { - set_marker_internal(seq); + set_marker_internal(seq.get()); } void Viewer::resizeEvent(QResizeEvent *e) { @@ -537,7 +537,7 @@ void Viewer::update_viewer() { void Viewer::clear_in() { if (seq != nullptr && seq->using_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(seq, true, 0, seq->workarea_out)); + olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), true, 0, seq->workarea_out)); update_parents(); } } @@ -545,7 +545,7 @@ void Viewer::clear_in() { void Viewer::clear_out() { if (seq != nullptr && seq->using_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(seq, true, seq->workarea_in, seq->getEndFrame())); + olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), true, seq->workarea_in, seq->getEndFrame())); update_parents(); } } @@ -553,7 +553,7 @@ void Viewer::clear_out() { void Viewer::clear_inout_point() { if (seq != nullptr && seq->using_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(seq, false, 0, 0)); + olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), false, 0, 0)); update_parents(); } } @@ -720,11 +720,11 @@ void Viewer::set_media(Media* m) { switch (media->get_type()) { case MEDIA_TYPE_FOOTAGE: { - FootagePtr footage = media->to_footage(); + Footage* footage = media->to_footage(); marker_ref = &footage->markers; - seq = SequencePtr(new Sequence()); + seq = std::make_shared(); created_sequence = true; seq->wrapper_sequence = true; seq->name = footage->name; @@ -744,7 +744,7 @@ void Viewer::set_media(Media* m) { 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 * footage->speed; - ClipPtr c = std::make_shared(seq); + ClipPtr c = std::make_shared(seq.get()); c->set_media(media, video_stream.file_index); c->set_timeline_in(0); c->set_timeline_out(footage->get_length_in_frames(seq->frame_rate)); @@ -766,7 +766,7 @@ void Viewer::set_media(Media* m) { const FootageStream& audio_stream = footage->audio_tracks.at(0); seq->audio_frequency = audio_stream.audio_frequency; - ClipPtr c = std::make_shared(seq); + ClipPtr c = std::make_shared(seq.get()); c->set_media(media, audio_stream.file_index); c->set_timeline_in(0); c->set_timeline_out(footage->get_length_in_frames(seq->frame_rate)); @@ -790,11 +790,11 @@ void Viewer::set_media(Media* m) { } break; case MEDIA_TYPE_SEQUENCE: - seq = media->to_sequence(); + seq = SequencePtr(media->to_sequence()); break; } } - set_sequence(false, seq); + set_sequence(false, seq.get()); } void Viewer::update_playhead() { @@ -857,17 +857,17 @@ void Viewer::clean_created_seq() { } } -void Viewer::set_sequence(bool main, SequencePtr s) { +void Viewer::set_sequence(bool main, Sequence* s) { pause(); reset_all_audio(); if (seq != nullptr) { - close_active_clips(seq); + close_active_clips(seq.get()); } main_sequence = main; - seq = (main) ? olive::ActiveSequence : s; + seq = SequencePtr((main) ? olive::ActiveSequence : s); bool null_sequence = (seq == nullptr); diff --git a/panels/viewer.h b/panels/viewer.h index 0f4ad5bb8..2b8bc2a76 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -126,7 +126,7 @@ private: void update_window_title(); void clean_created_seq(); - void set_sequence(bool main, SequencePtr s); + void set_sequence(bool main, Sequence *s); bool main_sequence; bool created_sequence; long cached_end_frame; diff --git a/project/clip.cpp b/project/clip.cpp index cf85fb55c..a85326cfe 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -38,7 +38,7 @@ const int kRGBAComponentCount = 4; -Clip::Clip(SequencePtr s) : +Clip::Clip(Sequence* s) : sequence(s), cacher(this) { @@ -62,7 +62,7 @@ Clip::Clip(SequencePtr s) : reset(); } -ClipPtr Clip::copy(SequencePtr s) { +ClipPtr Clip::copy(Sequence* s) { ClipPtr copy = std::make_shared(s); copy->set_enabled(enabled()); @@ -197,7 +197,7 @@ void Clip::reset_audio() { cacher.ResetAudio(); } if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) { - SequencePtr nested_sequence = media()->to_sequence(); + Sequence* nested_sequence = media()->to_sequence(); for (int i=0;iclips.size();i++) { ClipPtr c = nested_sequence->clips.at(i); if (c != nullptr) c->reset_audio(); @@ -208,7 +208,7 @@ void Clip::reset_audio() { void Clip::refresh() { // validates media if it was replaced if (replaced && media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE) { - FootagePtr m = media()->to_footage(); + Footage* m = media()->to_footage(); if (track() < 0 && m->video_tracks.size() > 0) { set_media(media(), m->video_tracks.at(0).file_index); @@ -231,6 +231,16 @@ QVector &Clip::get_markers() { return markers; } +int Clip::IndexOfEffect(Effect *e) +{ + for (int i=0;iget_type()) { case MEDIA_TYPE_FOOTAGE: { - FootagePtr m = media_->to_footage(); + Footage* m = media_->to_footage(); const FootageStream* ms = m->get_stream_from_file_index(track_ < 0, media_stream_index()); if (ms != nullptr && ms->infinite_length) { return LONG_MAX; @@ -381,7 +391,7 @@ long Clip::media_length() { } case MEDIA_TYPE_SEQUENCE: { - SequencePtr s = media_->to_sequence(); + Sequence* s = media_->to_sequence(); return rescale_frame_number(s->getEndFrame(), s->frame_rate, fr); } } @@ -402,7 +412,7 @@ int Clip::media_width() { } case MEDIA_TYPE_SEQUENCE: { - SequencePtr s = media_->to_sequence(); + Sequence* s = media_->to_sequence(); return s->width; } } @@ -421,7 +431,7 @@ int Clip::media_height() { break; case MEDIA_TYPE_SEQUENCE: { - SequencePtr s = media_->to_sequence(); + Sequence* s = media_->to_sequence(); return s->height; } } @@ -575,7 +585,7 @@ bool Clip::Retrieve() for (int i=0;iFlags() & Effect::ImageFlag) && e->is_enabled()) { + if ((e->Flags() & Effect::ImageFlag) && e->IsEnabled()) { if (data_buffer_1 == frame->data[0]) { data_buffer_1 = new uint8_t[frame_size]; data_buffer_2 = new uint8_t[frame_size]; diff --git a/project/clip.h b/project/clip.h index db2bf6c11..f7b52da8a 100644 --- a/project/clip.h +++ b/project/clip.h @@ -51,13 +51,12 @@ struct ClipSpeed { using ClipPtr = std::shared_ptr; class Sequence; -using SequencePtr = std::shared_ptr; -class Clip : public std::enable_shared_from_this { +class Clip { public: - Clip(SequencePtr s); + Clip(Sequence *s); ~Clip(); - ClipPtr copy(SequencePtr s); + ClipPtr copy(Sequence *s); bool IsActiveAt(long timecode); @@ -121,12 +120,13 @@ public: long length(); void refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points); - SequencePtr sequence; + Sequence* sequence; // markers QVector& get_markers(); // other variables (should be deep copied/duplicated in copy()) + int IndexOfEffect(Effect* e); QList effects; QVector linked; TransitionPtr opening_transition; diff --git a/project/effect.cpp b/project/effect.cpp index 74f41bf94..a54a2d4cc 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -73,32 +73,32 @@ EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { // must be an internal effect switch (em->internal) { - case EFFECT_INTERNAL_TRANSFORM: return std::make_shared(c, em); - case EFFECT_INTERNAL_TEXT: return std::make_shared(c, em); - case EFFECT_INTERNAL_TIMECODE: return std::make_shared(c, em); - case EFFECT_INTERNAL_SOLID: return std::make_shared(c, em); - case EFFECT_INTERNAL_NOISE: return std::make_shared(c, em); - case EFFECT_INTERNAL_VOLUME: return std::make_shared(c, em); - case EFFECT_INTERNAL_PAN: return std::make_shared(c, em); - case EFFECT_INTERNAL_TONE: return std::make_shared(c, em); - case EFFECT_INTERNAL_SHAKE: return std::make_shared(c, em); - case EFFECT_INTERNAL_CORNERPIN: return std::make_shared(c, em); - case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared(c, em); + case EFFECT_INTERNAL_TRANSFORM: return std::make_shared(c, em); + case EFFECT_INTERNAL_TEXT: return std::make_shared(c, em); + case EFFECT_INTERNAL_TIMECODE: return std::make_shared(c, em); + case EFFECT_INTERNAL_SOLID: return std::make_shared(c, em); + case EFFECT_INTERNAL_NOISE: return std::make_shared(c, em); + case EFFECT_INTERNAL_VOLUME: return std::make_shared(c, em); + case EFFECT_INTERNAL_PAN: return std::make_shared(c, em); + case EFFECT_INTERNAL_TONE: return std::make_shared(c, em); + case EFFECT_INTERNAL_SHAKE: return std::make_shared(c, em); + case EFFECT_INTERNAL_CORNERPIN: return std::make_shared(c, em); + case EFFECT_INTERNAL_FILLLEFTRIGHT: return std::make_shared(c, em); #ifndef NOVST - case EFFECT_INTERNAL_VST: return std::make_shared(c, em); + case EFFECT_INTERNAL_VST: return std::make_shared(c, em); #endif #ifndef NOFREI0R - case EFFECT_INTERNAL_FREI0R: return std::make_shared(c, em); + case EFFECT_INTERNAL_FREI0R: return std::make_shared(c, em); #endif } } else if (!em->filename.isEmpty()) { // load effect from file - return std::make_shared(c, em); + return std::make_shared(c, em); } else { qCritical() << "Invalid effect data"; - QMessageBox::critical(olive::MainWindow, - QCoreApplication::translate("Effect", "Invalid effect"), - QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); + QMessageBox::critical(olive::MainWindow, + QCoreApplication::translate("Effect", "Invalid effect"), + QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); } return nullptr; } @@ -123,19 +123,9 @@ Effect::Effect(Clip* c, const EffectMeta *em) : bound(false), iterations(1) { - // set up base UI - container = new CollapsibleWidget(); - connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); - ui = new QWidget(container); - ui_layout = new QGridLayout(ui); - ui_layout->setSpacing(4); - container->setContents(ui); - - connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); - if (em != nullptr) { // set up UI from effect file - container->setText(em->name); + name = em->name; if (!em->filename.isEmpty() && em->internal == -1) { QFile effect_file(em->filename); @@ -353,12 +343,12 @@ Effect::~Effect() { if (isOpen) { close(); } +} - delete container; - - for (int i=0;isetParent(this); + rows.append(row); } void Effect::copy_field_keyframes(EffectPtr e) { @@ -388,7 +378,7 @@ int Effect::row_count() { } EffectGizmo *Effect::add_gizmo(int type) { - EffectGizmo* gizmo = new EffectGizmo(type); + EffectGizmo* gizmo = new EffectGizmo(this, type); gizmos.append(gizmo); return gizmo; } @@ -408,83 +398,45 @@ void Effect::field_changed() { panel_graph_editor->update_panel(); } -void Effect::show_context_menu(const QPoint& pos) { - if (meta->type == EFFECT_TYPE_EFFECT) { - QMenu menu(olive::MainWindow); - - int index = get_index_in_clip(); - - menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); - menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); - - panel_effect_controls->add_effect_paste_action(&menu); - - menu.addSeparator(); - - if (index > 0) { - menu.addAction(tr("Move &Up"), this, SLOT(move_up())); - } - - if (index < parent_clip->effects.size() - 1) { - menu.addAction(tr("Move &Down"), this, SLOT(move_down())); - } - - menu.addSeparator(); - - menu.addAction(tr("D&elete"), this, SLOT(delete_self())); - - menu.addSeparator(); - - menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); - - menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); - - menu.exec(container->title_bar->mapToGlobal(pos)); - } -} - void Effect::delete_self() { - EffectDeleteCommand* command = new EffectDeleteCommand(); - command->clips.append(parent_clip); - command->fx.append(get_index_in_clip()); - olive::UndoStack.push(command); + olive::UndoStack.push(new EffectDeleteCommand(this)); update_ui(true); } void Effect::move_up() { MoveEffectCommand* command = new MoveEffectCommand(); command->clip = parent_clip; - command->from = get_index_in_clip(); + command->from = parent_clip->IndexOfEffect(this); command->to = command->from - 1; olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); + panel_effect_controls->Reload(); panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::move_down() { MoveEffectCommand* command = new MoveEffectCommand(); command->clip = parent_clip; - command->from = get_index_in_clip(); + command->from = parent_clip->IndexOfEffect(this); command->to = command->from + 1; olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); + panel_effect_controls->Reload(); panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::save_to_file() { // save effect settings to file - QString file = QFileDialog::getSaveFileName(olive::MainWindow, - tr("Save Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + QString file = QFileDialog::getSaveFileName(olive::MainWindow, + tr("Save Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); // if the user picked a file if (!file.isEmpty()) { - // ensure file ends with .xml extension - if (!file.endsWith(".xml", Qt::CaseInsensitive)) { - file.append(".xml"); - } + // ensure file ends with .xml extension + if (!file.endsWith(".xml", Qt::CaseInsensitive)) { + file.append(".xml"); + } QFile file_handle(file); if (file_handle.open(QFile::WriteOnly)) { @@ -493,36 +445,36 @@ void Effect::save_to_file() { file_handle.close(); } else { - QMessageBox::critical(olive::MainWindow, - tr("Save Settings Failed"), - tr("Failed to open \"%1\" for writing.").arg(file), - QMessageBox::Ok); + QMessageBox::critical(olive::MainWindow, + tr("Save Settings Failed"), + tr("Failed to open \"%1\" for writing.").arg(file), + QMessageBox::Ok); } } } void Effect::load_from_file() { // load effect settings from file - QString file = QFileDialog::getOpenFileName(olive::MainWindow, - tr("Load Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + QString file = QFileDialog::getOpenFileName(olive::MainWindow, + tr("Load Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); // if the user picked a file if (!file.isEmpty()) { QFile file_handle(file); if (file_handle.open(QFile::ReadOnly)) { - olive::UndoStack.push(new SetEffectData(EffectPtr(this), file_handle.readAll())); + olive::UndoStack.push(new SetEffectData(EffectPtr(this), file_handle.readAll())); file_handle.close(); update_ui(false); } else { - QMessageBox::critical(olive::MainWindow, - tr("Load Settings Failed"), - tr("Failed to open \"%1\" for reading.").arg(file), - QMessageBox::Ok); + QMessageBox::critical(olive::MainWindow, + tr("Load Settings Failed"), + tr("Failed to open \"%1\" for reading.").arg(file), + QMessageBox::Ok); } } } @@ -537,23 +489,13 @@ void Effect::SetAlwaysUpdate(bool b) enable_always_update_ = b; } -int Effect::get_index_in_clip() { - if (parent_clip != nullptr) { - for (int i=0;ieffects.size();i++) { - if (parent_clip->effects.at(i).get() == this) { - return i; - } - } - } - return -1; +bool Effect::IsEnabled() { + return enabled_; } -bool Effect::is_enabled() { - return container->enabled_check->isChecked(); -} - -void Effect::set_enabled(bool b) { - container->enabled_check->setChecked(b); +void Effect::SetEnabled(bool b) { + enabled_ = b; + emit EnabledChanged(b); } void Effect::load(QXmlStreamReader& stream) { @@ -649,7 +591,7 @@ void Effect::custom_load(QXmlStreamReader &) {} void Effect::save(QXmlStreamWriter& stream) { stream.writeAttribute("name", meta->category + "/" + meta->name); - stream.writeAttribute("enabled", QString::number(is_enabled())); + stream.writeAttribute("enabled", QString::number(IsEnabled())); for (int i=0;iset_enabled(is_enabled()); + EffectPtr copy = Effect::Create(c, meta); + copy->SetEnabled(IsEnabled()); copy_field_keyframes(copy); return copy; } @@ -894,7 +836,7 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { GLfloat(color_field->GetColorAt(timecode).redF()), GLfloat(color_field->GetColorAt(timecode).greenF()), GLfloat(color_field->GetColorAt(timecode).blueF()) - ); + ); } break; case EffectField::EFFECT_FIELD_BOOL: @@ -904,7 +846,7 @@ void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { glslProgram->setUniformValue(field->id().toUtf8().constData(), field->GetValueAt(timecode).toInt()); break; - // can you even send a string to a uniform value? + // can you even send a string to a uniform value? case EffectField::EFFECT_FIELD_STRING: case EffectField::EFFECT_FIELD_FONT: case EffectField::EFFECT_FIELD_FILE: @@ -1105,7 +1047,7 @@ const EffectMeta* get_meta_from_name(const QString& input) { for (int j=0;j rows; QVector gizmos; - QGridLayout* ui_layout; - QWidget* ui; bool bound; int iterations; + bool enabled_; + int flags_; // enable effect to update constantly @@ -255,15 +255,7 @@ private: bool valueHasChanged(double timecode); QVector cachedValues; void delete_texture(); - int get_index_in_clip(); void validate_meta_path(); }; -class EffectInit : public QThread { -public: - EffectInit(); -protected: - void run(); -}; - #endif // EFFECT_H diff --git a/project/effectfields/doublefield.cpp b/project/effectfields/doublefield.cpp index 783f65ed0..35b42835f 100644 --- a/project/effectfields/doublefield.cpp +++ b/project/effectfields/doublefield.cpp @@ -54,6 +54,11 @@ QString DoubleField::ConvertValueToString(const QVariant &v) return QString::number(v.toDouble()); } +//QWidget *DoubleField::CreateWidget() +//{ + +//} + void DoubleField::ValueHasBeenSet() { value_set_ = true; diff --git a/project/effectfields/doublefield.h b/project/effectfields/doublefield.h index c5deb0c21..4ef8d6762 100644 --- a/project/effectfields/doublefield.h +++ b/project/effectfields/doublefield.h @@ -34,6 +34,8 @@ public: virtual QVariant ConvertStringToValue(const QString& s); virtual QString ConvertValueToString(const QVariant& v); + + //virtual QWidget* CreateWidget() override; private: double min_; double max_; diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp index bb0536f20..094e86b74 100644 --- a/project/effectfields/effectfield.cpp +++ b/project/effectfields/effectfield.cpp @@ -151,6 +151,11 @@ QString EffectField::ConvertValueToString(const QVariant &v) return v.toString(); } +QWidget *EffectField::CreateWidget() +{ + return new QLabel(tr("(Invalid field)")); +} + QVariant EffectField::GetValueAt(double timecode) { Q_ASSERT(!keyframes.isEmpty()); diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h index c413078a7..c640d2124 100644 --- a/project/effectfields/effectfield.h +++ b/project/effectfields/effectfield.h @@ -61,6 +61,8 @@ public: virtual QVariant ConvertStringToValue(const QString& s); virtual QString ConvertValueToString(const QVariant& v); + virtual QWidget* CreateWidget(); + double GetValidKeyframeHandlePosition(int key, bool post); bool IsEnabled(); diff --git a/project/effectgizmo.cpp b/project/effectgizmo.cpp index b506eaf61..f2c8eba08 100644 --- a/project/effectgizmo.cpp +++ b/project/effectgizmo.cpp @@ -22,8 +22,10 @@ #include "ui/labelslider.h" #include "effectfields/doublefield.h" +#include "project/effect.h" -EffectGizmo::EffectGizmo(int type) : +EffectGizmo::EffectGizmo(Effect *parent, int type) : + QObject(parent), x_field1(nullptr), x_field_multi1(1.0), y_field1(nullptr), diff --git a/project/effectgizmo.h b/project/effectgizmo.h index 98a50962f..4fa854107 100644 --- a/project/effectgizmo.h +++ b/project/effectgizmo.h @@ -30,6 +30,7 @@ enum GizmoType { #define GIZMO_DOT_SIZE 2.5 #define GIZMO_TARGET_SIZE 5.0 +#include #include #include #include @@ -37,11 +38,12 @@ enum GizmoType { #include class DoubleField; +class Effect; -class EffectGizmo -{ +class EffectGizmo : public QObject { + Q_OBJECT public: - EffectGizmo(int type); + EffectGizmo(Effect* parent, int type); QVector world_pos; QVector screen_pos; diff --git a/project/effectloaders.h b/project/effectloaders.h index 9a4c2a86e..a5370df41 100644 --- a/project/effectloaders.h +++ b/project/effectloaders.h @@ -22,7 +22,15 @@ #define EFFECTLOADERS_H #include +#include void init_effects(); +class EffectInit : public QThread { +public: + EffectInit(); +protected: + void run(); +}; + #endif // EFFECTLOADERS_H diff --git a/project/effectrow.cpp b/project/effectrow.cpp index 2558ee326..779f97051 100644 --- a/project/effectrow.cpp +++ b/project/effectrow.cpp @@ -44,6 +44,8 @@ EffectRow::EffectRow(Effect *parent, const QString &n, bool savable, bool keyfra savable_(savable) { Q_ASSERT(parent != nullptr); + + parent->AddRow(this); } void EffectRow::AddField(EffectField *field) diff --git a/project/marker.cpp b/project/marker.cpp index e3a4f9dda..ef2cb5014 100644 --- a/project/marker.cpp +++ b/project/marker.cpp @@ -32,96 +32,96 @@ #include void draw_marker(QPainter &p, int x, int y, int bottom, bool selected) { - const QPoint points[5] = { - QPoint(x, bottom), - QPoint(x + MARKER_SIZE, bottom - MARKER_SIZE), - QPoint(x + MARKER_SIZE, y), - QPoint(x - MARKER_SIZE, y), - QPoint(x - MARKER_SIZE, bottom - MARKER_SIZE) - }; - p.setPen(Qt::black); - if (selected) { - p.setBrush(QColor(208, 255, 208)); - } else { - p.setBrush(QColor(128, 224, 128)); - } - p.drawPolygon(points, 5); + const QPoint points[5] = { + QPoint(x, bottom), + QPoint(x + MARKER_SIZE, bottom - MARKER_SIZE), + QPoint(x + MARKER_SIZE, y), + QPoint(x - MARKER_SIZE, y), + QPoint(x - MARKER_SIZE, bottom - MARKER_SIZE) + }; + p.setPen(Qt::black); + if (selected) { + p.setBrush(QColor(208, 255, 208)); + } else { + p.setBrush(QColor(128, 224, 128)); + } + p.drawPolygon(points, 5); } -void set_marker_internal(SequencePtr seq, const QVector& clips) { - // if clips is empty, the marker is being added to the sequence +void set_marker_internal(Sequence* seq, const QVector& clips) { + // if clips is empty, the marker is being added to the sequence - // add_marker is used to determine whether we're adding a marker, depending on whether the user input a marker name - // however if (config.set_name_with_marker) is true, we don't need a marker name so we just add - bool add_marker = !olive::CurrentConfig.set_name_with_marker; + // add_marker is used to determine whether we're adding a marker, depending on whether the user input a marker name + // however if (config.set_name_with_marker) is true, we don't need a marker name so we just add + bool add_marker = !olive::CurrentConfig.set_name_with_marker; - QString marker_name; + QString marker_name; - // if (config.set_name_with_marker) is false (set above), ask for a marker name - if (!add_marker) { + // if (config.set_name_with_marker) is false (set above), ask for a marker name + if (!add_marker) { QInputDialog d(olive::MainWindow); - d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); - d.setLabelText(clips.size() > 0 - ? QCoreApplication::translate("Marker", "Set clip marker name:") - : QCoreApplication::translate("Marker", "Set sequence marker name:")); - d.setInputMode(QInputDialog::TextInput); - add_marker = (d.exec() == QDialog::Accepted); - marker_name = d.textValue(); - } + d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); + d.setLabelText(clips.size() > 0 + ? QCoreApplication::translate("Marker", "Set clip marker name:") + : QCoreApplication::translate("Marker", "Set sequence marker name:")); + d.setInputMode(QInputDialog::TextInput); + add_marker = (d.exec() == QDialog::Accepted); + marker_name = d.textValue(); + } - // if we've decided to add a marker - if (add_marker) { + // if we've decided to add a marker + if (add_marker) { - ComboAction* ca = new ComboAction(); + ComboAction* ca = new ComboAction(); - if (clips.size() > 0) { + if (clips.size() > 0) { - // add a marker action for each clip - foreach (int i, clips) { + // add a marker action for each clip + foreach (int i, clips) { ClipPtr c = seq->clips.at(i); - ca->append(new AddMarkerAction(&c->get_markers(), + ca->append(new AddMarkerAction(&c->get_markers(), seq->playhead - c->timeline_in() + c->clip_in(), - marker_name)); - } + marker_name)); + } - } else { + } else { - // if no clips are selected, we're adding a marker to the sequence + // if no clips are selected, we're adding a marker to the sequence - // kind of hacky, we get the correct marker structure from the viewer panel object that the sequence is attached to - if (seq == panel_footage_viewer->seq) { + // kind of hacky, we get the correct marker structure from the viewer panel object that the sequence is attached to + if (seq == panel_footage_viewer->seq.get()) { - // get correct marker reference from footage viewer - ca->append(new AddMarkerAction(panel_footage_viewer->marker_ref, seq->playhead, marker_name)); + // get correct marker reference from footage viewer + ca->append(new AddMarkerAction(panel_footage_viewer->marker_ref, seq->playhead, marker_name)); - } else if (seq == panel_sequence_viewer->seq) { + } else if (seq == panel_sequence_viewer->seq.get()) { - // get correct marker reference from sequence viewer - ca->append(new AddMarkerAction(panel_sequence_viewer->marker_ref, seq->playhead, marker_name)); + // get correct marker reference from sequence viewer + ca->append(new AddMarkerAction(panel_sequence_viewer->marker_ref, seq->playhead, marker_name)); - } else { + } else { - // fallback to using markers from sequence provided - ca->append(new AddMarkerAction(&seq->markers, seq->playhead, marker_name)); + // fallback to using markers from sequence provided + ca->append(new AddMarkerAction(&seq->markers, seq->playhead, marker_name)); - } + } - } + } - // push action + // push action olive::UndoStack.push(ca); - // redraw UI for new markers - update_ui(false); - panel_footage_viewer->update_viewer(); + // redraw UI for new markers + update_ui(false); + panel_footage_viewer->update_viewer(); - } + } } -void set_marker_internal(SequencePtr seq) { - // create empty clip array - QVector clips; +void set_marker_internal(Sequence *seq) { + // create empty clip array + QVector clips; - set_marker_internal(seq, clips); + set_marker_internal(seq, clips); } diff --git a/project/marker.h b/project/marker.h index c2f7fe727..285f56773 100644 --- a/project/marker.h +++ b/project/marker.h @@ -37,7 +37,7 @@ struct Marker { void draw_marker(QPainter& p, int x, int y, int bottom, bool selected); -void set_marker_internal(SequencePtr seq, const QVector& clips); -void set_marker_internal(SequencePtr seq); +void set_marker_internal(Sequence *seq, const QVector& clips); +void set_marker_internal(Sequence* seq); #endif // MARKER_H diff --git a/project/media.cpp b/project/media.cpp index 354c4a4e9..ba8c747b8 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -73,12 +73,12 @@ Media::~Media() { } } -FootagePtr Media::to_footage() { - return std::static_pointer_cast(object); +Footage* Media::to_footage() { + return static_cast(object.get()); } -SequencePtr Media::to_sequence() { - return std::static_pointer_cast(object); +Sequence* Media::to_sequence() { + return static_cast(object.get()); } void Media::set_footage(FootagePtr f) { @@ -90,7 +90,9 @@ void Media::set_sequence(SequencePtr s) { set_icon(olive::icon::MediaSequence); type = MEDIA_TYPE_SEQUENCE; object = VoidPtr(s); - if (s != nullptr) update_tooltip(); + if (s != nullptr) { + update_tooltip(); + } } void Media::set_folder() { @@ -119,7 +121,7 @@ void Media::update_tooltip(const QString& error) { switch (type) { case MEDIA_TYPE_FOOTAGE: { - FootagePtr f = to_footage(); + Footage* f = to_footage(); tooltip = QCoreApplication::translate("Media", "Name:") + " " + f->name + "\n" + QCoreApplication::translate("Media", "Filename:") + " " + f->url + "\n"; if (error.isEmpty()) { @@ -190,7 +192,7 @@ void Media::update_tooltip(const QString& error) { break; case MEDIA_TYPE_SEQUENCE: { - SequencePtr s = to_sequence(); + Sequence* s = to_sequence(); tooltip = QCoreApplication::translate("Media", "Name: %1" "\nVideo Dimensions: %2x%3" @@ -238,7 +240,7 @@ double Media::get_frame_rate(int stream) { switch (get_type()) { case MEDIA_TYPE_FOOTAGE: { - FootagePtr f = to_footage(); + Footage* f = to_footage(); if (stream < 0) return f->video_tracks.at(0).video_frame_rate * f->speed; return f->get_stream_from_file_index(true, stream)->video_frame_rate * f->speed; } @@ -251,7 +253,7 @@ int Media::get_sampling_rate(int stream) { switch (get_type()) { case MEDIA_TYPE_FOOTAGE: { - FootagePtr f = to_footage(); + Footage* f = to_footage(); if (stream < 0) return f->audio_tracks.at(0).audio_frequency * f->speed; return to_footage()->get_stream_from_file_index(false, stream)->audio_frequency * f->speed; } @@ -293,7 +295,7 @@ QVariant Media::data(int column, int role) { case Qt::DecorationRole: if (column == 0) { if (get_type() == MEDIA_TYPE_FOOTAGE) { - FootagePtr f = to_footage(); + Footage* f = to_footage(); if (f->video_tracks.size() > 0 && f->video_tracks.at(0).preview_done) { return f->video_tracks.at(0).video_preview_square; @@ -309,11 +311,11 @@ QVariant Media::data(int column, int role) { case 1: if (root) return QCoreApplication::translate("Media", "Duration"); if (get_type() == MEDIA_TYPE_SEQUENCE) { - SequencePtr s = to_sequence(); + Sequence* s = to_sequence(); return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate); } if (get_type() == MEDIA_TYPE_FOOTAGE) { - FootagePtr f = to_footage(); + Footage* f = to_footage(); double r = 30; if (f->video_tracks.size() > 0 && !qIsNull(f->video_tracks.at(0).video_frame_rate)) @@ -327,7 +329,7 @@ QVariant Media::data(int column, int role) { if (root) return QCoreApplication::translate("Media", "Rate"); if (get_type() == MEDIA_TYPE_SEQUENCE) return QString::number(get_frame_rate()) + " FPS"; if (get_type() == MEDIA_TYPE_FOOTAGE) { - FootagePtr f = to_footage(); + Footage* f = to_footage(); double r; if (f->video_tracks.size() > 0 && !qIsNull(r = get_frame_rate())) { return QString::number(get_frame_rate()) + " FPS"; diff --git a/project/media.h b/project/media.h index 014aab03a..ba33a360d 100644 --- a/project/media.h +++ b/project/media.h @@ -44,8 +44,8 @@ class Media public: Media(Media* iparent); ~Media(); - FootagePtr to_footage(); - SequencePtr to_sequence(); + Footage *to_footage(); + Sequence *to_sequence(); void set_icon(const QString& str); void set_icon(const QIcon &ico); void set_footage(FootagePtr f); diff --git a/project/sequence.cpp b/project/sequence.cpp index dc3c8c83b..ddca16a04 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -22,6 +22,8 @@ #include +#include "panels/panels.h" + #include "debug.h" Sequence::Sequence() { @@ -35,7 +37,7 @@ Sequence::Sequence() { Sequence::~Sequence() {} SequencePtr Sequence::copy() { - SequencePtr s(new Sequence()); + SequencePtr s = std::make_shared(); s->name = QCoreApplication::translate("Sequence", "%1 (copy)").arg(name); s->width = width; s->height = height; @@ -50,7 +52,7 @@ SequencePtr Sequence::copy() { if (c == nullptr) { s->clips[i] = nullptr; } else { - ClipPtr copy = c->copy(s); + ClipPtr copy = c->copy(s.get()); copy->linked = c->linked; s->clips[i] = copy; } @@ -137,7 +139,7 @@ Effect *Sequence::GetSelectedGizmo() if (gizmo_ptr == nullptr) { gizmo_ptr = e; } - if (e->container->selected) { + if (panel_effect_controls->IsEffectSelected(e)) { gizmo_ptr = e; break; } @@ -190,4 +192,4 @@ void Sequence::getTrackLimits(int* video_tracks, int* audio_tracks) { } // static variable for the currently active sequence -SequencePtr olive::ActiveSequence = nullptr; +Sequence* olive::ActiveSequence = nullptr; diff --git a/project/sequence.h b/project/sequence.h index 1d8161061..385c92c42 100644 --- a/project/sequence.h +++ b/project/sequence.h @@ -71,7 +71,7 @@ using SequencePtr = std::shared_ptr; // static variable for the currently active sequence namespace olive { -extern SequencePtr ActiveSequence; + extern Sequence* ActiveSequence; } #endif // SEQUENCE_H diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index c2e12bf85..a48f80b88 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -65,8 +65,8 @@ void SourcesCommon::create_seq_from_selected() { SequencePtr s = create_sequence_from_media(media_list); // add clips to it - panel_timeline->create_ghosts_from_media(s, 0, media_list); - panel_timeline->add_clips_from_ghosts(ca, s); + panel_timeline->create_ghosts_from_media(s.get(), 0, media_list); + panel_timeline->add_clips_from_ghosts(ca, s.get()); project_parent->create_sequence_internal(ca, s, true, nullptr); olive::UndoStack.push(ca); @@ -342,7 +342,7 @@ void SourcesCommon::dropEvent(QWidget* parent, QDropEvent *event, const QModelIn void SourcesCommon::reveal_in_browser() { Media* media = project_parent->item_to_media(selected_items.at(0)); - FootagePtr m = media->to_footage(); + Footage* m = media->to_footage(); #if defined(Q_OS_WIN) QStringList args; @@ -405,7 +405,7 @@ void SourcesCommon::clear_proxies_from_selected() { QList delete_list; for (int i=0;ito_footage(); + Footage* f = cached_selected_footage.at(i)->to_footage(); if (f->proxy && !f->proxy_path.isEmpty()) { if (QFileInfo::exists(f->proxy_path)) { diff --git a/project/undo.cpp b/project/undo.cpp index e34eb697d..5863e111f 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -94,7 +94,7 @@ void MoveClipAction::doRedo() { } } -DeleteClipAction::DeleteClipAction(SequencePtr s, int clip) { +DeleteClipAction::DeleteClipAction(Sequence *s, int clip) { seq = s; index = clip; opening_transition = -1; @@ -140,7 +140,7 @@ void DeleteClipAction::doRedo() { } } -ChangeSequenceAction::ChangeSequenceAction(SequencePtr s) { +ChangeSequenceAction::ChangeSequenceAction(Sequence *s) { new_sequence = s; } @@ -153,7 +153,7 @@ void ChangeSequenceAction::doRedo() { olive::Global->set_sequence(new_sequence); } -SetTimelineInOutCommand::SetTimelineInOutCommand(SequencePtr s, bool enabled, long in, long out) { +SetTimelineInOutCommand::SetTimelineInOutCommand(Sequence* s, bool enabled, long in, long out) { seq = s; new_enabled = enabled; new_in = in; @@ -167,7 +167,7 @@ void SetTimelineInOutCommand::doUndo() { // footage viewer functions if (seq->wrapper_sequence) { - FootagePtr m = seq->clips.at(0)->media()->to_footage(); + Footage* m = seq->clips.at(0)->media()->to_footage(); m->using_inout = old_enabled; m->in = old_in; m->out = old_out; @@ -185,7 +185,7 @@ void SetTimelineInOutCommand::doRedo() { // footage viewer functions if (seq->wrapper_sequence) { - FootagePtr m = seq->clips.at(0)->media()->to_footage(); + Footage* m = seq->clips.at(0)->media()->to_footage(); m->using_inout = new_enabled; m->in = new_in; m->out = new_out; @@ -397,7 +397,7 @@ void DeleteMediaCommand::doRedo() { done = true; } -AddClipCommand::AddClipCommand(SequencePtr s, QVector& add) { +AddClipCommand::AddClipCommand(Sequence *s, QVector& add) { link_offset_ = 0; seq = s; clips = add; @@ -407,7 +407,7 @@ AddClipCommand::~AddClipCommand() {} void AddClipCommand::doUndo() { // clear effects panel - panel_effect_controls->clear_effects(true); + panel_effect_controls->Clear(true); for (int i=0;iclips.last(); @@ -514,7 +514,7 @@ void ReplaceMediaCommand::replace(QString& filename) { // close any clips currently using this media QVector all_sequences = panel_project->list_all_project_sequences(); for (int i=0;ito_sequence(); + Sequence* s = all_sequences.at(i)->to_sequence(); for (int j=0;jclips.size();j++) { ClipPtr c = s->clips.at(j); if (c != nullptr && c->media() == item && c->IsOpen()) { @@ -588,34 +588,28 @@ void ReplaceClipMediaCommand::doRedo() { update_ui(true); } -EffectDeleteCommand::EffectDeleteCommand() { - done = false; -} - -EffectDeleteCommand::~EffectDeleteCommand() {} +EffectDeleteCommand::EffectDeleteCommand(Effect *e) : + effect_(e) +{} void EffectDeleteCommand::doUndo() { - for (int i=0;ieffects.insert(fx.at(i), deleted_objects.at(i)); - } - panel_effect_controls->reload_clips(); - done = false; + parent_clip_->effects.insert(index_, deleted_obj_); + panel_effect_controls->Reload(); } void EffectDeleteCommand::doRedo() { - deleted_objects.clear(); - for (int i=0;ieffects.at(fx_id); - e->close(); - deleted_objects.append(e); - c->effects.removeAt(fx_id); - } - panel_effect_controls->reload_clips(); - done = true; + parent_clip_ = effect_->parent_clip; + + index_ = parent_clip_->IndexOfEffect(effect_); + + Q_ASSERT(index_ > -1); + + effect_->close(); + deleted_obj_ = parent_clip_->effects.at(index_); + parent_clip_->effects.removeAt(index_); + + panel_effect_controls->Reload(); } MediaMove::MediaMove() {} @@ -868,7 +862,7 @@ void SetBool::doRedo() { *boolean = new_setting; } -SetSelectionsCommand::SetSelectionsCommand(SequencePtr s) { +SetSelectionsCommand::SetSelectionsCommand(Sequence *s) { seq = s; done = true; } @@ -885,7 +879,7 @@ void SetSelectionsCommand::doRedo() { } } -EditSequenceCommand::EditSequenceCommand(Media* i, SequencePtr s) { +EditSequenceCommand::EditSequenceCommand(Media* i, Sequence *s) { item = i; seq = s; old_name = s->name; @@ -918,7 +912,8 @@ void EditSequenceCommand::doRedo() { void EditSequenceCommand::update() { // update tooltip - item->set_sequence(seq); + // TODO/FIXME: this is a lousy way to do this, Media should have a separate fuctionn for updating the tooltip + item->update_tooltip(); for (int i=0;iclips.size();i++) { if (seq->clips.at(i) != nullptr) seq->clips.at(i)->refresh(); @@ -1042,10 +1037,10 @@ void ReloadEffectsCommand::doUndo() { } void ReloadEffectsCommand::doRedo() { - panel_effect_controls->reload_clips(); + panel_effect_controls->Reload(); } -RippleAction::RippleAction(SequencePtr is, long ipoint, long ilength, const QVector &iignore) { +RippleAction::RippleAction(Sequence *is, long ipoint, long ilength, const QVector &iignore) { s = is; point = ipoint; length = ilength; @@ -1161,7 +1156,7 @@ void RefreshClips::doRedo() { // close any clips currently using this media QVector all_sequences = panel_project->list_all_project_sequences(); for (int i=0;ito_sequence(); + Sequence* s = all_sequences.at(i)->to_sequence(); for (int j=0;jclips.size();j++) { ClipPtr c = s->clips.at(j); if (c != nullptr && c->media() == media) { diff --git a/project/undo.h b/project/undo.h index efb9b9d4f..d2ba4d0dd 100644 --- a/project/undo.h +++ b/project/undo.h @@ -84,11 +84,11 @@ private: class RippleAction : public OliveAction { public: - RippleAction(SequencePtr is, long ipoint, long ilength, const QVector& iignore); + RippleAction(Sequence* is, long ipoint, long ilength, const QVector& iignore); virtual void doUndo() override; virtual void doRedo() override; private: - SequencePtr s; + Sequence* s; long point; long length; QVector ignore; @@ -97,12 +97,12 @@ private: class DeleteClipAction : public OliveAction { public: - DeleteClipAction(SequencePtr s, int clip); + DeleteClipAction(Sequence* s, int clip); virtual ~DeleteClipAction() override; virtual void doUndo() override; virtual void doRedo() override; private: - SequencePtr seq; + Sequence* seq; ClipPtr ref; int index; @@ -115,12 +115,12 @@ private: class ChangeSequenceAction : public OliveAction { public: - ChangeSequenceAction(SequencePtr s); + ChangeSequenceAction(Sequence* s); virtual void doUndo() override; virtual void doRedo() override; private: - SequencePtr old_sequence; - SequencePtr new_sequence; + Sequence* old_sequence; + Sequence* new_sequence; }; class AddEffectCommand : public OliveAction { @@ -176,11 +176,11 @@ private: class SetTimelineInOutCommand : public OliveAction { public: - SetTimelineInOutCommand(SequencePtr s, bool enabled, long in, long out); + SetTimelineInOutCommand(Sequence* s, bool enabled, long in, long out); virtual void doUndo() override; virtual void doRedo() override; private: - SequencePtr seq; + Sequence* seq; bool old_enabled; long old_in; @@ -229,12 +229,12 @@ private: class AddClipCommand : public OliveAction { public: - AddClipCommand(SequencePtr s, QVector& add); + AddClipCommand(Sequence* s, QVector& add); virtual ~AddClipCommand() override; virtual void doUndo() override; virtual void doRedo() override; private: - SequencePtr seq; + Sequence* seq; QVector clips; int link_offset_; }; @@ -244,7 +244,7 @@ public: LinkCommand(); virtual void doUndo() override; virtual void doRedo() override; - SequencePtr s; + Sequence* s; QVector clips; bool link; private: @@ -291,15 +291,14 @@ private: class EffectDeleteCommand : public OliveAction { public: - EffectDeleteCommand(); - virtual ~EffectDeleteCommand() override; + EffectDeleteCommand(Effect* e); virtual void doUndo() override; virtual void doRedo() override; - QVector clips; - QVector fx; private: - bool done; - QVector deleted_objects; + Effect* effect_; + EffectPtr deleted_obj_; + Clip* parent_clip_; + int index_; }; class MediaMove : public OliveAction { @@ -444,19 +443,19 @@ private: class SetSelectionsCommand : public OliveAction { public: - SetSelectionsCommand(SequencePtr s); + SetSelectionsCommand(Sequence* s); virtual void doUndo() override; virtual void doRedo() override; QVector old_data; QVector new_data; private: - SequencePtr seq; + Sequence* seq; bool done; }; class EditSequenceCommand : public OliveAction { public: - EditSequenceCommand(Media *i, SequencePtr s); + EditSequenceCommand(Media *i, Sequence* s); virtual void doUndo() override; virtual void doRedo() override; void update(); @@ -469,7 +468,7 @@ public: int audio_layout; private: Media* item; - SequencePtr seq; + Sequence* seq; QString old_name; int old_width; diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index 380b1c996..7c2460eed 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -56,8 +56,10 @@ void apply_audio_effects(Clip* clip, double timecode_start, AVFrame* frame, int timecode_end = timecode_start + bytes_to_seconds(nb_bytes, frame->channels, frame->sample_rate); for (int j=0;jeffects.size();j++) { - EffectPtr e = clip->effects.at(j); - if (e->is_enabled()) e->process_audio(timecode_start, timecode_end, frame->data[0], nb_bytes, 2); + Effect* e = clip->effects.at(j).get(); + if (e->IsEnabled()) { + e->process_audio(timecode_start, timecode_end, frame->data[0], nb_bytes, 2); + } } if (clip->opening_transition != nullptr) { if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { @@ -839,7 +841,7 @@ void Cacher::OpenWorker() { } } else if (clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { // opens file resource for FFmpeg and prepares Clip struct for playback - FootagePtr m = clip->media()->to_footage(); + Footage* m = clip->media()->to_footage(); // byte array for retriving raw bytes from QString URL QByteArray ba; diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 68d91073c..deb51acf5 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -114,7 +114,7 @@ void process_effect(Clip* c, bool& fbo_switcher, bool& texture_failed, int data) { - if (e->is_enabled()) { + if (e->IsEnabled()) { if (e->Flags() & Effect::CoordsFlag) { e->process_coords(timecode, coords, data); } @@ -159,7 +159,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { GLuint final_fbo = params.main_buffer; - SequencePtr s = params.seq; + Sequence* s = params.seq; long playhead = s->playhead; if (!params.nests.isEmpty()) { @@ -194,7 +194,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // is the clip a "footage" clip? if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) { - FootagePtr m = c->media()->to_footage(); + Footage* m = c->media()->to_footage(); // does the clip have a valid media source? if (!m->invalid && !(c->track() >= 0 && !is_audio_device_set())) { @@ -658,7 +658,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { return 0; } -void compose_audio(Viewer* viewer, SequencePtr seq, int playback_speed, bool wait_for_mutexes) { +void compose_audio(Viewer* viewer, Sequence* seq, int playback_speed, bool wait_for_mutexes) { ComposeSequenceParams params; params.viewer = viewer; params.ctx = nullptr; @@ -707,7 +707,7 @@ int64_t playhead_to_timestamp(Clip* c, long playhead) { return seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead)); } -void close_active_clips(SequencePtr s) { +void close_active_clips(Sequence* s) { if (s != nullptr) { for (int i=0;iclips.size();i++) { Clip* c = s->clips.at(i).get(); diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h index 3c1f49734..21507c990 100644 --- a/rendering/renderfunctions.h +++ b/rendering/renderfunctions.h @@ -59,7 +59,7 @@ struct ComposeSequenceParams { * In addition to clips, sequences also contain the playhead position so compose_sequence() knows which frame * to render. */ - SequencePtr seq; + Sequence* seq; /** * @brief Array to store the nested sequence hierarchy @@ -263,7 +263,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms); * * Whether to wait for media to open or simply fail if the media is not yet open. This should usually be **FALSE**. */ -void compose_audio(Viewer* viewer, SequencePtr seq, int playback_speed, bool wait_for_mutexes); +void compose_audio(Viewer* viewer, Sequence *seq, int playback_speed, bool wait_for_mutexes); /** * @brief Rescale a frame number between two frame rates @@ -400,6 +400,6 @@ int64_t playhead_to_timestamp(Clip *c, long playhead); * * The Sequence to close all clips on. */ -void close_active_clips(SequencePtr s); +void close_active_clips(Sequence* s); #endif // RENDERFUNCTIONS_H diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 0c3ff96f3..7dc2f0715 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -230,7 +230,12 @@ void RenderThread::paint() { ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } -void RenderThread::start_render(QOpenGLContext *share, SequencePtr s, const QString& save, GLvoid* pixels, int pixel_linesize, int idivider) { +void RenderThread::start_render(QOpenGLContext *share, + Sequence* s, + const QString& save, + GLvoid* pixels, + int pixel_linesize, + int idivider) { Q_UNUSED(idivider); seq = s; diff --git a/rendering/renderthread.h b/rendering/renderthread.h index e18be91d3..8f0d9c3a4 100644 --- a/rendering/renderthread.h +++ b/rendering/renderthread.h @@ -52,7 +52,7 @@ public: Effect* gizmos; void paint(); void start_render(QOpenGLContext* share, - SequencePtr s, + Sequence *s, const QString &save = nullptr, GLvoid *pixels = nullptr, int pixel_linesize = 0, @@ -101,7 +101,7 @@ private: GLuint ocio_lut_texture; QOpenGLShaderProgram* ocio_shader; - SequencePtr seq; + Sequence* seq; int divider; int tex_width; int tex_height; diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index 07292287d..dd0e9ced9 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -53,7 +53,7 @@ CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { collapse_button = new QPushButton(title_bar); collapse_button->setIconSize(collapse_button->iconSize()*0.5); collapse_button->setStyleSheet("QPushButton { border: none; }"); - setText(tr("")); + SetText(tr("")); title_bar_layout->addWidget(collapse_button); title_bar_layout->addWidget(enabled_check); title_bar_layout->addWidget(header); @@ -80,20 +80,25 @@ void CollapsibleWidget::header_click(bool s, bool deselect) { if (deselect) emit deselect_others(this); } -bool CollapsibleWidget::is_focused() { +bool CollapsibleWidget::IsFocused() { if (hasFocus()) return true; return title_bar->hasFocus(); } -bool CollapsibleWidget::is_expanded() { +bool CollapsibleWidget::IsExpanded() { return contents->isVisible(); } +bool CollapsibleWidget::IsSelected() +{ + return selected; +} + void CollapsibleWidget::set_button_icon(bool open) { collapse_button->setIcon(open ? olive::icon::DownArrow : olive::icon::RightArrow); } -void CollapsibleWidget::setContents(QWidget* c) { +void CollapsibleWidget::SetContents(QWidget* c) { bool existing = (contents != nullptr); contents = c; if (!existing) { @@ -103,7 +108,7 @@ void CollapsibleWidget::setContents(QWidget* c) { } } -void CollapsibleWidget::setText(const QString &s) { +void CollapsibleWidget::SetText(const QString &s) { header->setText(s); } diff --git a/ui/collapsiblewidget.h b/ui/collapsiblewidget.h index c506ce153..74b5d3502 100644 --- a/ui/collapsiblewidget.h +++ b/ui/collapsiblewidget.h @@ -35,7 +35,7 @@ class CollapsibleWidgetHeader : public QWidget { Q_OBJECT public: - CollapsibleWidgetHeader(QWidget* parent = 0); + CollapsibleWidgetHeader(QWidget* parent = nullptr); bool selected; protected: void mousePressEvent(QMouseEvent* event); @@ -48,17 +48,18 @@ class CollapsibleWidget : public QWidget { Q_OBJECT public: - CollapsibleWidget(QWidget* parent = 0); - void setContents(QWidget* c); - void setText(const QString &); - bool is_focused(); - bool is_expanded(); - + CollapsibleWidget(QWidget* parent = nullptr); + void SetContents(QWidget* c); + void SetText(const QString &); + bool IsFocused(); + bool IsExpanded(); + bool IsSelected(); +protected: CheckboxEx* enabled_check; - bool selected; - QWidget* contents; CollapsibleWidgetHeader* title_bar; private: + bool selected; + QWidget* contents; QLabel* header; QVBoxLayout* layout; QPushButton* collapse_button; diff --git a/ui/effectui.cpp b/ui/effectui.cpp new file mode 100644 index 000000000..c8dcdc9d8 --- /dev/null +++ b/ui/effectui.cpp @@ -0,0 +1,94 @@ +#include "effectui.h" + +#include +#include + +#include "project/clip.h" +#include "ui/menuhelper.h" + +EffectUI::EffectUI(Effect* e) : + effect_(e) +{ + Q_ASSERT(e != nullptr); + + SetText(e->name); + + QWidget* ui = new QWidget(this); + SetContents(ui); + + layout_ = new QGridLayout(ui); + layout_->setSpacing(4); + + connect(title_bar, + SIGNAL(customContextMenuRequested(const QPoint&)), + this, + SIGNAL(TitleBarContextMenuRequested(const QPoint&))); + + for (int i=0;irow_count();i++) { + EffectRow* row = e->row(i); + + QLabel* row_label = new QLabel(row->name()); + + labels_.append(row_label); + + layout_->addWidget(row_label, i, 0); + + for (int j=0;jFieldCount();j++) { + EffectField* field = row->Field(j); + + QWidget* widget = field->CreateWidget(); + + layout_->addWidget(widget, i, j + 1); + } + } + + connect(enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); +} + +Effect *EffectUI::GetEffect() +{ + return effect_; +} + +int EffectUI::GetRowPos(int row) +{ + QLabel* row_label = labels_.at(row); + return mapToGlobal(row_label->rect().center()).y(); +} + +void EffectUI::show_context_menu(const QPoint& pos) { + if (effect_->meta->type == EFFECT_TYPE_EFFECT) { + QMenu menu; + + Clip* c = effect_->parent_clip; + + int index = c->IndexOfEffect(effect_); + + menu.addAction(tr("Cu&t"), this, SIGNAL(CutRequested())); + menu.addAction(tr("&Copy"), this, SIGNAL(CopyRequested())); + + olive::MenuHelper.create_effect_paste_action(&menu); + + menu.addSeparator(); + + if (index > 0) { + menu.addAction(tr("Move &Up"), this, SLOT(move_up())); + } + + if (index < c->effects.size() - 1) { + menu.addAction(tr("Move &Down"), this, SLOT(move_down())); + } + + menu.addSeparator(); + + menu.addAction(tr("D&elete"), this, SLOT(delete_self())); + + menu.addSeparator(); + + menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); + + menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); + + menu.exec(title_bar->mapToGlobal(pos)); + } +} diff --git a/ui/effectui.h b/ui/effectui.h new file mode 100644 index 000000000..3191fc90c --- /dev/null +++ b/ui/effectui.h @@ -0,0 +1,27 @@ +#ifndef EFFECTUI_H +#define EFFECTUI_H + +#include "collapsiblewidget.h" +#include "project/effect.h" + +class EffectUI : public CollapsibleWidget { + Q_OBJECT +public: + EffectUI(Effect* e); + + Effect* GetEffect(); + + int GetRowPos(int row); +signals: + void CutRequested(); + void CopyRequested(); + void TitleBarContextMenuRequested(const QPoint&); +private: + Effect* effect_; + QGridLayout* layout_; + QVector labels_; +private slots: + void show_context_menu(const QPoint&); +}; + +#endif // EFFECTUI_H diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index dd36d8343..b0a0beb46 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -23,7 +23,6 @@ #include "project/effect.h" #include "ui/collapsiblewidget.h" #include "panels/panels.h" -#include "panels/effectcontrols.h" #include "project/clip.h" #include "panels/timeline.h" #include "ui/timelineheader.h" @@ -62,6 +61,11 @@ KeyframeView::KeyframeView(QWidget *parent) : connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); } +void KeyframeView::SetEffects(const QVector &open_effects) +{ + open_effects_ = open_effects; +} + void KeyframeView::show_context_menu(const QPoint& pos) { if (selected_fields.size() > 0) { QMenu menu(this); @@ -101,73 +105,61 @@ void KeyframeView::paintEvent(QPaintEvent*) { rowY.clear(); rows.clear(); - if (panel_effect_controls->selected_clips.size() > 0) { + if (!open_effects_.isEmpty()) { visible_in = LONG_MAX; visible_out = 0; - for (int j=0;jselected_clips.size();j++) { - ClipPtr c = olive::ActiveSequence->clips.at(panel_effect_controls->selected_clips.at(j)); + for (int i=0;iGetEffect()->parent_clip; visible_in = qMin(visible_in, c->timeline_in()); visible_out = qMax(visible_out, c->timeline_out()); } - for (int j=0;jselected_clips.size();j++) { - ClipPtr c = olive::ActiveSequence->clips.at(panel_effect_controls->selected_clips.at(j)); - for (int i=0;ieffects.size();i++) { - EffectPtr e = c->effects.at(i); - if (e->container->is_expanded()) { - for (int j=0;jrow_count();j++) { - EffectRow* row = e->row(j); + for (int j=0;jGetEffect(); - /* + if (container->IsExpanded()) { + for (int j=0;jrow_count();j++) { + EffectRow* row = e->row(j); - ClickableLabel* label = row->label; - QWidget* contents = e->container->contents; + int keyframe_y = container->GetRowPos(j); - QVector key_times; + QVector 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(); + for (int l=0;lFieldCount();l++) { + EffectField* f = row->Field(l); + for (int k=0;kkeyframes.size();k++) { + if (!key_times.contains(f->keyframes.at(k).time)) { + bool keyframe_selected = keyframeIsSelected(f, k); + long keyframe_frame = adjust_row_keyframe(row, f->keyframes.at(k).time, visible_in); - for (int l=0;lFieldCount();l++) { - EffectField* f = row->Field(l); - for (int k=0;kkeyframes.size();k++) { - if (!key_times.contains(f->keyframes.at(k).time)) { - bool keyframe_selected = keyframeIsSelected(f, k); - long keyframe_frame = adjust_row_keyframe(row, f->keyframes.at(k).time, visible_in); - - // see if any other keyframes have this time - int appearances = 0; - for (int m=0;mFieldCount();m++) { - EffectField* compf = row->Field(m); - for (int n=0;nkeyframes.size();n++) { - if (f->keyframes.at(k).time == compf->keyframes.at(n).time) { - appearances++; - } + // see if any other keyframes have this time + int appearances = 0; + for (int m=0;mFieldCount();m++) { + EffectField* compf = row->Field(m); + for (int n=0;nkeyframes.size();n++) { + if (f->keyframes.at(k).time == compf->keyframes.at(n).time) { + appearances++; } } - - if (appearances != row->FieldCount()) { - 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); } + + if (appearances != row->FieldCount()) { + 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); - rowY.append(keyframe_y); - - */ } + + rows.append(row); + rowY.append(keyframe_y); } } } diff --git a/ui/keyframeview.h b/ui/keyframeview.h index b704aa1d1..645861ec8 100644 --- a/ui/keyframeview.h +++ b/ui/keyframeview.h @@ -24,6 +24,8 @@ #include #include +#include "ui/effectui.h" + class Clip; class Effect; class EffectRow; @@ -31,56 +33,60 @@ class EffectField; class TimelineHeader; class KeyframeView : public QWidget { - Q_OBJECT + Q_OBJECT public: - KeyframeView(QWidget* parent = 0); + KeyframeView(QWidget* parent = nullptr); - void delete_selected_keyframes(); + void SetEffects(const QVector& open_effects); - TimelineHeader* header; + void delete_selected_keyframes(); - long visible_in; - long visible_out; + TimelineHeader* header; + + long visible_in; + long visible_out; signals: - void wheel_event_signal(QWheelEvent*); + void wheel_event_signal(QWheelEvent*); public slots: - void set_x_scroll(int); - void set_y_scroll(int); - void resize_move(double d); + void set_x_scroll(int); + void set_y_scroll(int); + void resize_move(double d); private: - QVector selected_fields; - QVector selected_keyframes; - QVector rowY; - QVector rows; - QVector old_key_vals; - void mousePressEvent(QMouseEvent* event); - void mouseMoveEvent(QMouseEvent* event); - void mouseReleaseEvent(QMouseEvent *event); - void paintEvent(QPaintEvent *event); - void wheelEvent(QWheelEvent* e); - bool mousedown; - bool dragging; - bool keys_selected; - bool select_rect; - bool scroll_drag; + QVector open_effects_; - bool keyframeIsSelected(EffectField *field, int keyframe); + QVector selected_fields; + QVector selected_keyframes; + QVector rowY; + QVector rows; + QVector old_key_vals; + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent *event); + void paintEvent(QPaintEvent *event); + void wheelEvent(QWheelEvent* e); + bool mousedown; + bool dragging; + bool keys_selected; + bool select_rect; + bool scroll_drag; - long drag_frame_start; - long last_frame_diff; - int rect_select_x; - int rect_select_y; - int rect_select_w; - int rect_select_h; - int rect_select_offset; + bool keyframeIsSelected(EffectField *field, int keyframe); - int x_scroll; - int y_scroll; + long drag_frame_start; + long last_frame_diff; + int rect_select_x; + int rect_select_y; + int rect_select_w; + int rect_select_h; + int rect_select_offset; - void update_keys(); + int x_scroll; + int y_scroll; + + void update_keys(); private slots: - void show_context_menu(const QPoint& pos); - void menu_set_key_type(QAction*); + void show_context_menu(const QPoint& pos); + void menu_set_key_type(QAction*); }; #endif // KEYFRAMEVIEW_H diff --git a/ui/menuhelper.cpp b/ui/menuhelper.cpp index 6cb2ed788..aad6a8fac 100644 --- a/ui/menuhelper.cpp +++ b/ui/menuhelper.cpp @@ -20,21 +20,18 @@ #include "menuhelper.h" -#include "oliveglobal.h" - -#include "ui/focusfilter.h" - -#include "io/config.h" - -#include "panels/panels.h" - -#include "mainwindow.h" - #include #include #include #include +#include "io/config.h" +#include "io/clipboard.h" +#include "mainwindow.h" +#include "oliveglobal.h" +#include "panels/panels.h" +#include "ui/focusfilter.h" + MenuHelper olive::MenuHelper; void MenuHelper::InitializeSharedMenus() @@ -262,6 +259,12 @@ void MenuHelper::open_recent_from_menu() { olive::Global.get()->open_recent(index); } +void MenuHelper::create_effect_paste_action(QMenu *menu) +{ + QAction* paste_action = menu->addAction(tr("&Paste"), panel_timeline, SLOT(paste(bool))); + paste_action->setEnabled(clipboard.size() > 0 && clipboard_type == CLIPBOARD_TYPE_EFFECT); +} + QMenu* MenuHelper::create_submenu(QMenuBar* parent, const QObject *receiver, const char *member) { diff --git a/ui/menuhelper.h b/ui/menuhelper.h index 9fdf42aa8..e1a14d0d9 100644 --- a/ui/menuhelper.h +++ b/ui/menuhelper.h @@ -186,6 +186,15 @@ public slots: */ void open_recent_from_menu(); + /** + * @brief Create a "Paste" action on the specified menu that's enabled only if the clipboard contains effects + * + * @param menu + * + * Menu to add action to + */ + void create_effect_paste_action(QMenu *menu); + private: QAction* new_project_; QAction* new_sequence_; diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index b3e3711c2..f32621ea7 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -115,7 +115,7 @@ void TimelineHeader::set_in_point(long new_in) { new_out = viewer->seq->getEndFrame(); } - olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq, true, new_in, new_out)); + olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); update_parents(); } @@ -127,7 +127,7 @@ void TimelineHeader::set_out_point(long new_out) { new_in = 0; } - olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq, true, new_in, new_out)); + olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, new_in, new_out)); update_parents(); } @@ -280,7 +280,7 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { if (viewer->seq != nullptr) { dragging = false; if (resizing_workarea) { - olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq, true, temp_workarea_in, temp_workarea_out)); + olive::UndoStack.push(new SetTimelineInOutCommand(viewer->seq.get(), true, temp_workarea_in, temp_workarea_out)); } else if (dragging_markers && selected_markers.size() > 0) { bool moved = false; ComboAction* ca = new ComboAction(); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 828f2d5e1..fbb2d3100 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -259,7 +259,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { } if (event->source() == panel_footage_viewer->viewer_widget) { - SequencePtr proposed_seq = panel_footage_viewer->seq; + Sequence* proposed_seq = panel_footage_viewer->seq.get(); if (proposed_seq != olive::ActiveSequence) { // don't allow nesting the same sequence media_list.append(panel_footage_viewer->media); import_init = true; @@ -280,7 +280,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { for (int i=0;ilast_imported_media.size();i++) { // waits for media to have a duration // TODO would be much nicer if this was multithreaded - FootagePtr f = panel_project->last_imported_media.at(i)->to_footage(); + Footage* f = panel_project->last_imported_media.at(i)->to_footage(); f->ready_lock.lock(); f->ready_lock.unlock(); @@ -302,14 +302,14 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { event->acceptProposedAction(); long entry_point; - SequencePtr seq = olive::ActiveSequence; + Sequence* seq = olive::ActiveSequence; if (seq == nullptr) { // if no sequence, we're going to create a new one using the clips as a reference entry_point = 0; self_created_sequence = create_sequence_from_media(media_list); - seq = self_created_sequence; + seq = self_created_sequence.get(); } else { entry_point = panel_timeline->getTimelineFrameFromScreenPoint(event->pos().x()); panel_timeline->drag_frame_start = entry_point + getFrameFromScreenPoint(panel_timeline->zoom, 50); @@ -515,11 +515,11 @@ void TimelineWidget::dropEvent(QDropEvent* event) { ComboAction* ca = new ComboAction(); - SequencePtr s = olive::ActiveSequence; + Sequence* s = olive::ActiveSequence; // if we're dropping into nothing, create a new sequences based on the clip being dragged if (s == nullptr) { - s = self_created_sequence; + s = self_created_sequence.get(); panel_project->create_sequence_internal(ca, self_created_sequence, true, nullptr); self_created_sequence = nullptr; } else if (event->keyboardModifiers() & Qt::ControlModifier) { @@ -2953,7 +2953,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { bool draw_checkerboard = false; QRect checkerboard_rect(clip_rect); - FootagePtr m = clip->media()->to_footage(); + Footage* m = clip->media()->to_footage(); FootageStream* ms = clip->media_stream(); if (ms == nullptr) { draw_checkerboard = true; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index eb3f139c7..0ac1d6dfa 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -91,7 +91,7 @@ ViewerWidget::~ViewerWidget() { } void ViewerWidget::delete_function() { - close_active_clips(viewer->seq); + close_active_clips(viewer->seq.get()); } void ViewerWidget::set_waveform_scroll(int s) { @@ -168,7 +168,7 @@ void ViewerWidget::save_frame() { fn += selected_ext; } - renderer->start_render(context(), viewer->seq, fn); + renderer->start_render(context(), viewer->seq.get(), fn); } } @@ -228,11 +228,11 @@ void ViewerWidget::frame_update() { update(); } else { doneCurrent(); - renderer->start_render(context(), viewer->seq); + renderer->start_render(context(), viewer->seq.get()); } // render the audio - compose_audio(viewer, viewer->seq, viewer->get_playback_speed(), viewer->WaitingForPlayWake()); + compose_audio(viewer, viewer->seq.get(), viewer->get_playback_speed(), viewer->WaitingForPlayWake()); } } @@ -253,7 +253,7 @@ void ViewerWidget::seek_from_click(int x) { void ViewerWidget::context_destroy() { makeCurrent(); if (viewer->seq != nullptr) { - close_active_clips(viewer->seq); + close_active_clips(viewer->seq.get()); } renderer->delete_ctx(); doneCurrent(); @@ -619,7 +619,7 @@ void ViewerWidget::paintGL() { if (renderer->did_texture_fail() && !viewer->playing) { doneCurrent(); - renderer->start_render(context(), viewer->seq); + renderer->start_render(context(), viewer->seq.get()); } } } From e3e45279b92e93dbf17a79d4a704304a19fbc9c0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 00:12:15 +1100 Subject: [PATCH 04/56] reimplemented double and bool widgets separately --- dialogs/exportdialog.cpp | 2 +- dialogs/newsequencedialog.h | 2 +- dialogs/speeddialog.cpp | 8 +- effects/internal/transformeffect.cpp | 2 +- io/exportthread.cpp | 4 +- io/loadthread.cpp | 2 +- io/loadthread.h | 2 +- oliveglobal.cpp | 2 +- oliveglobal.h | 2 +- panels/effectcontrols.cpp | 15 +- panels/project.cpp | 20 ++- panels/timeline.cpp | 48 +++--- panels/viewer.cpp | 14 +- panels/viewer.h | 2 +- project/clip.cpp | 16 +- project/effect.cpp | 8 +- project/effect.h | 2 +- project/effectfields/boolfield.cpp | 18 ++ project/effectfields/boolfield.h | 6 + project/effectfields/doublefield.cpp | 34 +++- project/effectfields/doublefield.h | 3 +- project/effectfields/effectfield.cpp | 86 ++-------- project/effectfields/effectfield.h | 4 +- project/media.cpp | 8 +- project/media.h | 2 +- project/sequence.cpp | 2 +- project/sequence.h | 2 +- project/sourcescommon.cpp | 2 +- project/undo.cpp | 14 +- project/undo.h | 14 +- rendering/renderfunctions.cpp | 4 +- ui/effectui.cpp | 9 +- ui/labelslider.cpp | 6 +- ui/labelslider.h | 248 +++++++++++++-------------- ui/timelinewidget.cpp | 24 ++- ui/viewerwidget.cpp | 2 +- 36 files changed, 327 insertions(+), 312 deletions(-) diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index 97eae5b25..b37f6f4f2 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -543,7 +543,7 @@ void ExportDialog::export_action() { connect(et, SIGNAL(finished()), this, SLOT(render_thread_finished())); connect(et, SIGNAL(progress_changed(int, qint64)), this, SLOT(update_progress_bar(int, qint64))); - close_active_clips(olive::ActiveSequence); + close_active_clips(olive::ActiveSequence.get()); olive::Global->set_rendering_state(true); diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h index b77fa0852..ec7ab84b8 100644 --- a/dialogs/newsequencedialog.h +++ b/dialogs/newsequencedialog.h @@ -45,7 +45,7 @@ private slots: void preset_changed(int index); private: - Sequence* existing_sequence; + SequencePtr existing_sequence; Media* existing_item; void setup_ui(); diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index 6f38cea38..c2233fa9d 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -79,9 +79,9 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(percent, SIGNAL(valueChanged()), this, SLOT(percent_update())); - connect(frame_rate, SIGNAL(valueChanged()), this, SLOT(frame_rate_update())); - connect(duration, SIGNAL(valueChanged()), this, SLOT(duration_update())); + connect(percent, SIGNAL(valueChanged(double)), this, SLOT(percent_update())); + connect(frame_rate, SIGNAL(valueChanged(double)), this, SLOT(frame_rate_update())); + connect(duration, SIGNAL(valueChanged(double)), this, SLOT(duration_update())); } void SpeedDialog::run() { @@ -356,7 +356,7 @@ void SpeedDialog::accept() { SetClipProperty* reversed_action = new SetClipProperty(kSetClipPropertyReversed); // undoable action for restoring clip selections - SetSelectionsCommand* sel_command = new SetSelectionsCommand(olive::ActiveSequence); + SetSelectionsCommand* sel_command = new SetSelectionsCommand(olive::ActiveSequence.get()); sel_command->old_data = olive::ActiveSequence->selections; // variables used to calculate ripples diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 4043f2ba0..82103cfe9 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -137,7 +137,7 @@ TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) rect_gizmo->x_field1 = position_x; 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 uniform_scale_field->SetValueAt(0, true); diff --git a/io/exportthread.cpp b/io/exportthread.cpp index ab2c689cc..05fff530d 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -377,12 +377,12 @@ void ExportThread::run() { start_time = QDateTime::currentMSecsSinceEpoch(); if (params.audio_enabled) { - compose_audio(nullptr, olive::ActiveSequence, 1, true); + compose_audio(nullptr, olive::ActiveSequence.get(), 1, true); } if (params.video_enabled) { do { // TODO optimize by rendering the next frame while encoding the last - renderer->start_render(nullptr, olive::ActiveSequence, nullptr, video_frame->data[0], video_frame->linesize[0]/4); + renderer->start_render(nullptr, olive::ActiveSequence.get(), nullptr, video_frame->data[0], video_frame->linesize[0]/4); waitCond.wait(&mutex); if (!continueEncode) break; } while (renderer->did_texture_fail()); diff --git a/io/loadthread.cpp b/io/loadthread.cpp index fa23eb733..5aab007ea 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -372,7 +372,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } else if (attr.name() == "alayout") { s->audio_layout = attr.value().toInt(); } else if (attr.name() == "open") { - open_seq = s.get(); + open_seq = s; } else if (attr.name() == "workarea") { s->using_workarea = (attr.value() == "1"); } else if (attr.name() == "workareaIn") { diff --git a/io/loadthread.h b/io/loadthread.h index 2ecd4a593..14b92e7b2 100644 --- a/io/loadthread.h +++ b/io/loadthread.h @@ -72,7 +72,7 @@ private: void read_next_start_element(QXmlStreamReader& stream); void update_current_element_count(QXmlStreamReader& stream); - Sequence* open_seq; + SequencePtr open_seq; QVector loaded_media_items; QDir proj_dir; QDir internal_proj_dir; diff --git a/oliveglobal.cpp b/oliveglobal.cpp index b293f79e0..07dd08970 100644 --- a/oliveglobal.cpp +++ b/oliveglobal.cpp @@ -286,7 +286,7 @@ void OliveGlobal::open_preferences() { pd.exec(); } -void OliveGlobal::set_sequence(Sequence* s) +void OliveGlobal::set_sequence(SequencePtr s) { panel_effect_controls->Clear(true); diff --git a/oliveglobal.h b/oliveglobal.h index 2cfd348f8..305beefb8 100644 --- a/oliveglobal.h +++ b/oliveglobal.h @@ -274,7 +274,7 @@ public slots: * * The Sequence to set as the active Sequence. */ - void set_sequence(Sequence *s); + void set_sequence(SequencePtr s); private: /** diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index ab155daea..d82822d67 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -258,12 +258,15 @@ void EffectControls::Clear(bool clear_cache) { deselect_all_effects(nullptr); // clear graph editor - if (panel_graph_editor != nullptr) panel_graph_editor->set_row(nullptr); + if (panel_graph_editor != nullptr) { + panel_graph_editor->set_row(nullptr); + } for (int i=0;iSetEffects(open_effects_); vcontainer->setVisible(false); acontainer->setVisible(false); @@ -295,14 +298,16 @@ void EffectControls::deselect_all_effects(QWidget* sender) { } } - panel_sequence_viewer->viewer_widget->update(); + if (panel_sequence_viewer != nullptr) { + panel_sequence_viewer->viewer_widget->update(); + } } void EffectControls::open_effect(QVBoxLayout* layout, Effect* e) { EffectUI* container = new EffectUI(e); connect(container, SIGNAL(CutRequested()), this, SLOT(cut())); - connect(container, SIGNAL(CopyRequested()), this, SLOT(copy(bool))); + connect(container, SIGNAL(CopyRequested()), this, SLOT(copy())); connect(container, SIGNAL(deselect_others(QWidget*)), this, SLOT(deselect_all_effects(QWidget*))); open_effects_.append(container); @@ -596,8 +601,12 @@ void EffectControls::Load() { open_effect(layout, c->closing_transition.get()); } } + + keyframeView->SetEffects(open_effects_); + if (selected_clips_.size() > 0) { keyframeView->setEnabled(true); + headers->setVisible(true); QTimer::singleShot(50, this, SLOT(queue_post_update())); diff --git a/panels/project.cpp b/panels/project.cpp index 1806c1354..0966c4ce7 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -292,7 +292,9 @@ SequencePtr create_sequence_from_media(QVector& media_list) { break; case MEDIA_TYPE_SEQUENCE: { - Sequence* seq = media->to_sequence(); + // Clone all attributes of the original sequence (seq) into the new one (s) + Sequence* seq = media->to_sequence().get(); + s->width = seq->width; s->height = seq->height; s->frame_rate = seq->frame_rate; @@ -442,13 +444,13 @@ Media* Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool op ca->append(new NewSequenceCommand(item, parent)); if (open) { - ca->append(new ChangeSequenceAction(s.get())); + ca->append(new ChangeSequenceAction(s)); } } else { olive::project_model.appendChild(parent, item); if (open) { - olive::Global->set_sequence(s.get()); + olive::Global->set_sequence(s); } } return item; @@ -535,7 +537,7 @@ void Project::delete_selected_media() { Footage* media = item->to_footage(); bool confirm_delete = false; for (int j=0;jto_sequence(); + Sequence* s = sequence_items.at(j)->to_sequence().get(); for (int k=0;kclips.size();k++) { ClipPtr c = s->clips.at(k); if (c != nullptr && c->media() == item) { @@ -621,9 +623,9 @@ void Project::delete_selected_media() { if (items.at(i)->get_type() == MEDIA_TYPE_SEQUENCE) { redraw = true; - Sequence* s = items.at(i)->to_sequence(); + Sequence* s = items.at(i)->to_sequence().get(); - if (s == olive::ActiveSequence) { + if (s == olive::ActiveSequence.get()) { ca->append(new ChangeSequenceAction(nullptr)); } @@ -990,7 +992,7 @@ void Project::delete_clips_using_selected_media() { for (int j=0;jmedia() == m) { - ca->append(new DeleteClipAction(olive::ActiveSequence, i)); + ca->append(new DeleteClipAction(olive::ActiveSequence.get(), i)); deleted = true; } } @@ -1129,7 +1131,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, stream.writeEndElement(); // footage media_id++; } else if (type == MEDIA_TYPE_SEQUENCE) { - Sequence* s = m->to_sequence(); + Sequence* s = m->to_sequence().get(); if (set_ids_only) { s->save_id = sequence_id; sequence_id++; @@ -1143,7 +1145,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, stream.writeAttribute("framerate", QString::number(s->frame_rate, 'f', 10)); stream.writeAttribute("afreq", QString::number(s->audio_frequency)); stream.writeAttribute("alayout", QString::number(s->audio_layout)); - if (s == olive::ActiveSequence) { + if (s == olive::ActiveSequence.get()) { stream.writeAttribute("open", "1"); } stream.writeAttribute("workarea", QString::number(s->using_workarea)); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 9de1f4154..4170246e8 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -219,7 +219,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector } break; case MEDIA_TYPE_SEQUENCE: - s = medium->to_sequence(); + s = medium->to_sequence().get(); sequence_length = s->getEndFrame(); if (seq != nullptr) sequence_length = rescale_frame_number(sequence_length, s->frame_rate, seq->frame_rate); can_import = (s != seq && sequence_length != 0); @@ -330,8 +330,7 @@ void Timeline::add_clips_from_ghosts(ComboAction* ca, Sequence* s) { // sequence (red?ish?) c->set_color(192, 128, 128); - Sequence* media = c->media()->to_sequence(); - c->set_name(media->name); + c->set_name(c->media()->to_sequence()->name); } c->refresh(); added_clips.append(c); @@ -432,7 +431,7 @@ void Timeline::nest() { // copy all selected clips to the nest for (int i=0;iappend(new DeleteClipAction(olive::ActiveSequence, selected_clips.at(i))); + ca->append(new DeleteClipAction(olive::ActiveSequence.get(), selected_clips.at(i))); // copy to new ClipPtr copy(olive::ActiveSequence->clips.at(selected_clips.at(i))->copy(s.get())); @@ -450,8 +449,8 @@ void Timeline::nest() { // add nested sequence to active sequence QVector media_list; media_list.append(m); - create_ghosts_from_media(olive::ActiveSequence, earliest_point, media_list); - add_clips_from_ghosts(ca, olive::ActiveSequence); + create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list); + add_clips_from_ghosts(ca, olive::ActiveSequence.get()); panel_effect_controls->Clear(true); olive::ActiveSequence->selections.clear(); @@ -648,8 +647,11 @@ void Timeline::delete_in_out_internal(bool ripple) { } ComboAction* ca = new ComboAction(); delete_areas_and_relink(ca, areas, true); - if (ripple) ripple_clips(ca, olive::ActiveSequence, olive::ActiveSequence->workarea_in, olive::ActiveSequence->workarea_in - olive::ActiveSequence->workarea_out); - ca->append(new SetTimelineInOutCommand(olive::ActiveSequence, false, 0, 0)); + if (ripple) ripple_clips(ca, + olive::ActiveSequence.get(), + olive::ActiveSequence->workarea_in, + olive::ActiveSequence->workarea_in - olive::ActiveSequence->workarea_out); + ca->append(new SetTimelineInOutCommand(olive::ActiveSequence.get(), false, 0, 0)); olive::UndoStack.push(ca); update_ui(true); } @@ -732,7 +734,7 @@ void Timeline::delete_selection(QVector& selections, bool ripple_dele } if (can_ripple) { - ripple_clips(ca, olive::ActiveSequence, ripple_point, -ripple_length); + ripple_clips(ca, olive::ActiveSequence.get(), ripple_point, -ripple_length); panel_sequence_viewer->seek(ripple_point-1); } @@ -851,7 +853,7 @@ ClipPtr Timeline::split_clip(ComboAction* ca, bool transitions, int p, long fram if (pre->timeline_in() < frame && pre->timeline_out() > frame) { // duplicate clip without duplicating its transitions, we'll restore them later - ClipPtr post = ClipPtr(pre->copy(olive::ActiveSequence)); + ClipPtr post = pre->copy(olive::ActiveSequence.get()); long new_clip_length = frame - pre->timeline_in(); @@ -961,7 +963,7 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool relink_clips_using_ids(pre_clips, post_clips); } - ca->append(new AddClipCommand(olive::ActiveSequence, post_clips)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips)); return true; } } @@ -1032,7 +1034,7 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector& area ca->append(new DeleteTransitionCommand(c->closing_transition)); } else if (c->timeline_in() >= s.in && c->timeline_out() <= s.out) { // clips falls entirely within deletion area - ca->append(new DeleteClipAction(olive::ActiveSequence, j)); + ca->append(new DeleteClipAction(olive::ActiveSequence.get(), j)); } else if (c->timeline_in() < s.in && c->timeline_out() > s.out) { // middle of clip is within deletion area @@ -1078,7 +1080,7 @@ void Timeline::delete_areas_and_relink(ComboAction* ca, QVector& area } relink_clips_using_ids(pre_clips, post_clips); - ca->append(new AddClipCommand(olive::ActiveSequence, post_clips)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips)); } void Timeline::copy(bool del) { @@ -1171,7 +1173,7 @@ void Timeline::paste(bool insert) { ClipPtr c = std::static_pointer_cast(clipboard.at(i)); // create copy of clip and offset by playhead - ClipPtr cc(c->copy(olive::ActiveSequence)); + ClipPtr cc = c->copy(olive::ActiveSequence.get()); // convert frame rates cc->set_timeline_in(rescale_frame_number(cc->timeline_in(), c->cached_frame_rate(), olive::ActiveSequence->frame_rate)); @@ -1198,7 +1200,7 @@ void Timeline::paste(bool insert) { if (insert) { split_cache.clear(); split_all_clips_at_point(ca, olive::ActiveSequence->playhead); - ripple_clips(ca, olive::ActiveSequence, paste_start, paste_end - paste_start); + ripple_clips(ca, olive::ActiveSequence.get(), paste_start, paste_end - paste_start); } else { delete_areas_and_relink(ca, delete_areas, false); } @@ -1218,7 +1220,7 @@ void Timeline::paste(bool insert) { } } - ca->append(new AddClipCommand(olive::ActiveSequence, pasted_clips)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), pasted_clips)); olive::UndoStack.push(ca); @@ -1367,7 +1369,7 @@ void Timeline::edit_to_point_internal(bool in, bool ripple) { // trim and move clips around the in point delete_areas_and_relink(ca, areas, true); - if (ripple) ripple_clips(ca, olive::ActiveSequence, in_point, -1); + if (ripple) ripple_clips(ca, olive::ActiveSequence.get(), in_point, -1); } else { push_undo = false; } @@ -1391,7 +1393,7 @@ void Timeline::edit_to_point_internal(bool in, bool ripple) { // trim and move clips around the in point delete_areas_and_relink(ca, areas, true); - if (ripple) ripple_clips(ca, olive::ActiveSequence, s.in, s.in - s.out); + if (ripple) ripple_clips(ca, olive::ActiveSequence.get(), s.in, s.in - s.out); } } @@ -1449,8 +1451,8 @@ bool Timeline::split_selection(ComboAction* ca) { relink_clips_using_ids(pre_splits, post_splits); relink_clips_using_ids(pre_splits, secondary_post_splits); - ca->append(new AddClipCommand(olive::ActiveSequence, post_splits)); - ca->append(new AddClipCommand(olive::ActiveSequence, secondary_post_splits)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_splits)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), secondary_post_splits)); return true; } @@ -1495,7 +1497,7 @@ void Timeline::split_at_playhead() { if (split_selected) { // relink clips if we split relink_clips_using_ids(pre_clips, post_clips); - ca->append(new AddClipCommand(olive::ActiveSequence, post_clips)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips)); } else { // split a selection if not split_selected = split_selection(ca); @@ -1646,7 +1648,7 @@ void Timeline::set_marker() { } // pass off to internal set marker function - set_marker_internal(olive::ActiveSequence, clips_selected); + set_marker_internal(olive::ActiveSequence.get(), clips_selected); } @@ -1676,7 +1678,7 @@ void Timeline::edit_to_out_point() { void Timeline::toggle_links() { LinkCommand* command = new LinkCommand(); - command->s = olive::ActiveSequence; + command->s = olive::ActiveSequence.get(); for (int i=0;iclips.size();i++) { Clip* c = olive::ActiveSequence->clips.at(i).get(); if (c != nullptr && olive::ActiveSequence->IsClipSelected(c, true)) { diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 8cf5db31a..dce62dd18 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -83,7 +83,7 @@ Viewer::Viewer(QWidget *parent) : current_timecode_slider->set_default_value(qSNaN()); current_timecode_slider->set_value(0, false); current_timecode_slider->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); - connect(current_timecode_slider, SIGNAL(valueChanged()), this, SLOT(update_playhead())); + connect(current_timecode_slider, SIGNAL(valueChanged(double)), this, SLOT(update_playhead())); recording_flasher.setInterval(500); @@ -790,11 +790,11 @@ void Viewer::set_media(Media* m) { } break; case MEDIA_TYPE_SEQUENCE: - seq = SequencePtr(media->to_sequence()); + seq = media->to_sequence(); break; } } - set_sequence(false, seq.get()); + set_sequence(false, seq); } void Viewer::update_playhead() { @@ -857,17 +857,19 @@ void Viewer::clean_created_seq() { } } -void Viewer::set_sequence(bool main, Sequence* s) { +void Viewer::set_sequence(bool main, SequencePtr s) { pause(); reset_all_audio(); + main_sequence = main; + + // If we had a current sequence open, close it if (seq != nullptr) { close_active_clips(seq.get()); } - main_sequence = main; - seq = SequencePtr((main) ? olive::ActiveSequence : s); + seq = (main) ? olive::ActiveSequence : s; bool null_sequence = (seq == nullptr); diff --git a/panels/viewer.h b/panels/viewer.h index 2b8bc2a76..0f4ad5bb8 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -126,7 +126,7 @@ private: void update_window_title(); void clean_created_seq(); - void set_sequence(bool main, Sequence *s); + void set_sequence(bool main, SequencePtr s); bool main_sequence; bool created_sequence; long cached_end_frame; diff --git a/project/clip.cpp b/project/clip.cpp index a85326cfe..a1cef5d25 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -197,10 +197,12 @@ void Clip::reset_audio() { cacher.ResetAudio(); } if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) { - Sequence* nested_sequence = media()->to_sequence(); + Sequence* nested_sequence = media()->to_sequence().get(); for (int i=0;iclips.size();i++) { - ClipPtr c = nested_sequence->clips.at(i); - if (c != nullptr) c->reset_audio(); + Clip* c = nested_sequence->clips.at(i).get(); + if (c != nullptr) { + c->reset_audio(); + } } } } @@ -391,7 +393,7 @@ long Clip::media_length() { } case MEDIA_TYPE_SEQUENCE: { - Sequence* s = media_->to_sequence(); + Sequence* s = media_->to_sequence().get(); return rescale_frame_number(s->getEndFrame(), s->frame_rate, fr); } } @@ -412,7 +414,7 @@ int Clip::media_width() { } case MEDIA_TYPE_SEQUENCE: { - Sequence* s = media_->to_sequence(); + Sequence* s = media_->to_sequence().get(); return s->width; } } @@ -431,7 +433,7 @@ int Clip::media_height() { break; case MEDIA_TYPE_SEQUENCE: { - Sequence* s = media_->to_sequence(); + Sequence* s = media_->to_sequence().get(); return s->height; } } @@ -489,7 +491,7 @@ void Clip::Close(bool wait) { open_ = false; if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) { - close_active_clips(media()->to_sequence()); + close_active_clips(media()->to_sequence().get()); } // destroy opengl texture in main thread diff --git a/project/effect.cpp b/project/effect.cpp index a54a2d4cc..f32598be5 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -290,10 +290,6 @@ Effect::Effect(Clip* c, const EffectMeta *em) : } break; } - - if (field != nullptr) { - connect(field, SIGNAL(changed()), this, SLOT(field_changed())); - } } } } @@ -393,7 +389,7 @@ int Effect::gizmo_count() { void Effect::refresh() {} -void Effect::field_changed() { +void Effect::FieldChanged() { panel_sequence_viewer->viewer_widget->frame_update(); panel_graph_editor->update_panel(); } @@ -465,7 +461,7 @@ void Effect::load_from_file() { QFile file_handle(file); if (file_handle.open(QFile::ReadOnly)) { - olive::UndoStack.push(new SetEffectData(EffectPtr(this), file_handle.readAll())); + olive::UndoStack.push(new SetEffectData(this, file_handle.readAll())); file_handle.close(); diff --git a/project/effect.h b/project/effect.h index b74c34825..e7c9ca99f 100644 --- a/project/effect.h +++ b/project/effect.h @@ -214,7 +214,7 @@ public: static EffectPtr Create(Clip *c, const EffectMeta *em); static const EffectMeta* GetInternalMeta(int internal_id, int type); public slots: - void field_changed(); + void FieldChanged(); signals: void EnabledChanged(bool); private slots: diff --git a/project/effectfields/boolfield.cpp b/project/effectfields/boolfield.cpp index e230c7ad7..0a15030c4 100644 --- a/project/effectfields/boolfield.cpp +++ b/project/effectfields/boolfield.cpp @@ -1,5 +1,7 @@ #include "boolfield.h" +#include + BoolField::BoolField(EffectRow *parent, const QString &id) : EffectField(parent, id, EFFECT_FIELD_BOOL) {} @@ -9,6 +11,17 @@ bool BoolField::GetBoolAt(double timecode) return GetValueAt(timecode).toBool(); } +QWidget *BoolField::CreateWidget() +{ + QCheckBox* cb = new QCheckBox(); + + connect(cb, SIGNAL(toggled(bool)), this, SLOT(UpdateFromWidget(bool))); + connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); + connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(Toggled(bool))); + + return cb; +} + QVariant BoolField::ConvertStringToValue(const QString &s) { return (s == "1"); @@ -18,3 +31,8 @@ QString BoolField::ConvertValueToString(const QVariant &v) { return QString::number(v.toBool()); } + +void BoolField::UpdateFromWidget(bool b) +{ + SetValueAt(Now(), b); +} diff --git a/project/effectfields/boolfield.h b/project/effectfields/boolfield.h index d61ef33e9..bf6be11d7 100644 --- a/project/effectfields/boolfield.h +++ b/project/effectfields/boolfield.h @@ -11,8 +11,14 @@ public: bool GetBoolAt(double timecode); + virtual QWidget* CreateWidget() override; + virtual QVariant ConvertStringToValue(const QString& s) override; virtual QString ConvertValueToString(const QVariant& v) override; +signals: + void Toggled(bool); +private slots: + void UpdateFromWidget(bool b); }; #endif // BOOLFIELD_H diff --git a/project/effectfields/doublefield.cpp b/project/effectfields/doublefield.cpp index 35b42835f..a0e9260e1 100644 --- a/project/effectfields/doublefield.cpp +++ b/project/effectfields/doublefield.cpp @@ -2,8 +2,11 @@ DoubleField::DoubleField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_DOUBLE), - min_(DBL_MIN), - max_(DBL_MAX), + min_(qSNaN()), + max_(qSNaN()), + default_(0), + display_type_(LabelSlider::LABELSLIDER_NORMAL), + frame_rate_(30), value_set_(false) { connect(this, SIGNAL(Changed()), this, SLOT(ValueHasBeenSet()), Qt::DirectConnection); @@ -54,12 +57,33 @@ QString DoubleField::ConvertValueToString(const QVariant &v) return QString::number(v.toDouble()); } -//QWidget *DoubleField::CreateWidget() -//{ +QWidget *DoubleField::CreateWidget() +{ + LabelSlider* ls = new LabelSlider(); -//} + if (!qIsNaN(min_)) { + ls->set_minimum_value(min_); + } + ls->set_default_value(default_); + if (!qIsNaN(max_)) { + ls->set_maximum_value(max_); + } + ls->set_display_type(display_type_); + ls->set_frame_rate(frame_rate_); + + connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double))); + connect(ls, SIGNAL(clicked()), this, SIGNAL(Clicked())); + connect(this, SIGNAL(EnabledChanged(bool)), ls, SLOT(setEnabled(bool))); + + return ls; +} void DoubleField::ValueHasBeenSet() { value_set_ = true; } + +void DoubleField::UpdateFromWidget(double d) +{ + SetValueAt(Now(), d); +} diff --git a/project/effectfields/doublefield.h b/project/effectfields/doublefield.h index 4ef8d6762..2935cf4d6 100644 --- a/project/effectfields/doublefield.h +++ b/project/effectfields/doublefield.h @@ -35,7 +35,7 @@ public: virtual QVariant ConvertStringToValue(const QString& s); virtual QString ConvertValueToString(const QVariant& v); - //virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget() override; private: double min_; double max_; @@ -47,6 +47,7 @@ private: bool value_set_; private slots: void ValueHasBeenSet(); + void UpdateFromWidget(double d); }; #endif // DOUBLEFIELD_H diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp index 094e86b74..b71154022 100644 --- a/project/effectfields/effectfield.cpp +++ b/project/effectfields/effectfield.cpp @@ -20,6 +20,9 @@ #include "effectfield.h" +#include +#include + #include "ui/labelslider.h" #include "ui/colorbutton.h" #include "ui/texteditex.h" @@ -28,6 +31,8 @@ #include "ui/fontcombobox.h" #include "ui/embeddedfilechooser.h" +#include "rendering/renderfunctions.h" + #include "io/config.h" #include "project/effectrow.h" @@ -39,9 +44,6 @@ #include "io/math.h" -#include -#include - #include "debug.h" EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) : @@ -54,74 +56,14 @@ EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) Q_ASSERT(parent != nullptr); Q_ASSERT(!i.isEmpty() || t == EFFECT_FIELD_UI); + // Add this field to the parent row specified parent->AddField(this); - /* - switch (t) { - case EFFECT_FIELD_DOUBLE: - { - LabelSlider* ls = new LabelSlider(); - ui_element = ls; - connect(ls, SIGNAL(valueChanged()), this, SLOT(ui_element_change())); - connect(ls, SIGNAL(clicked()), this, SIGNAL(clicked())); - } - break; - case EFFECT_FIELD_COLOR: - { - ColorButton* cb = new ColorButton(); - ui_element = cb; - connect(cb, SIGNAL(color_changed()), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_STRING: - { - TextEditEx* edit = new TextEditEx(); - - // TODO magic number 2 - It seems to just be +1 for the top and +1 for the bottom, which is sort of sensible but - // feels a little tacky? - edit->setFixedHeight(qCeil(edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines - + edit->document()->documentMargin() - + edit->document()->documentMargin() - + 2)); - - edit->setUndoRedoEnabled(true); - ui_element = edit; - connect(edit, SIGNAL(textChanged()), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_BOOL: - { - CheckboxEx* cb = new CheckboxEx(); - ui_element = cb; - connect(cb, SIGNAL(clicked(bool)), this, SLOT(ui_element_change())); - connect(cb, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); - } - break; - case EFFECT_FIELD_COMBO: - { - ComboBoxEx* cb = new ComboBoxEx(); - ui_element = cb; - connect(cb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_FONT: - { - FontCombobox* fcb = new FontCombobox(); - ui_element = fcb; - connect(fcb, SIGNAL(activated(int)), this, SLOT(ui_element_change())); - } - break; - case EFFECT_FIELD_FILE: - { - EmbeddedFileChooser* efc = new EmbeddedFileChooser(); - ui_element = efc; - connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change())); - } - break; - } - */ // Set a very base default value SetValueAt(0, 0); + + // Connect this field to the effect's changed function + connect(this, SIGNAL(Changed()), parent->GetParentEffect(), SLOT(FieldChanged())); } EffectField::~EffectField() {} @@ -223,6 +165,8 @@ QVariant EffectField::GetValueAt(double timecode) case EFFECT_FIELD_FONT: case EFFECT_FIELD_FILE: return before_data; + default: + break; } } @@ -247,6 +191,12 @@ void EffectField::SetValueAt(double timecode, const QVariant &value) emit Changed(); } +double EffectField::Now() +{ + Clip* c = GetParentRow()->GetParentEffect()->parent_clip; + return playhead_to_clip_seconds(c, c->sequence->playhead); +} + const EffectField::EffectFieldType &EffectField::type() { return type_; @@ -351,6 +301,7 @@ bool EffectField::HasKeyframes() { return (GetParentRow()->IsKeyframing() && keyframes.size() > 1); } +/* void EffectField::ui_element_change() { // TODO address this //bool dragging_double = (type_ == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); @@ -361,6 +312,7 @@ void EffectField::ui_element_change() { if (!dragging_double) olive::UndoStack.push(ca); emit Changed(); } +*/ /* void EffectField::make_key_from_change(ComboAction* ca) { diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h index c640d2124..166c801e0 100644 --- a/project/effectfields/effectfield.h +++ b/project/effectfields/effectfield.h @@ -55,6 +55,8 @@ public: QVariant GetValueAt(double timecode); void SetValueAt(double timecode, const QVariant& value); + double Now(); + int GetColumnSpan(); void SetColumnSpan(int i); @@ -69,8 +71,6 @@ public: void SetEnabled(bool e); QVector keyframes; -public slots: - void ui_element_change(); private: EffectFieldType type_; QString id_; diff --git a/project/media.cpp b/project/media.cpp index ba8c747b8..b9d4508a2 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -77,8 +77,8 @@ Footage* Media::to_footage() { return static_cast(object.get()); } -Sequence* Media::to_sequence() { - return static_cast(object.get()); +SequencePtr Media::to_sequence() { + return std::static_pointer_cast(object); } void Media::set_footage(FootagePtr f) { @@ -192,7 +192,7 @@ void Media::update_tooltip(const QString& error) { break; case MEDIA_TYPE_SEQUENCE: { - Sequence* s = to_sequence(); + Sequence* s = to_sequence().get(); tooltip = QCoreApplication::translate("Media", "Name: %1" "\nVideo Dimensions: %2x%3" @@ -311,7 +311,7 @@ QVariant Media::data(int column, int role) { case 1: if (root) return QCoreApplication::translate("Media", "Duration"); if (get_type() == MEDIA_TYPE_SEQUENCE) { - Sequence* s = to_sequence(); + Sequence* s = to_sequence().get(); return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate); } if (get_type() == MEDIA_TYPE_FOOTAGE) { diff --git a/project/media.h b/project/media.h index ba33a360d..b4f6c628d 100644 --- a/project/media.h +++ b/project/media.h @@ -45,7 +45,7 @@ public: Media(Media* iparent); ~Media(); Footage *to_footage(); - Sequence *to_sequence(); + SequencePtr to_sequence(); void set_icon(const QString& str); void set_icon(const QIcon &ico); void set_footage(FootagePtr f); diff --git a/project/sequence.cpp b/project/sequence.cpp index ddca16a04..a604146db 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -192,4 +192,4 @@ void Sequence::getTrackLimits(int* video_tracks, int* audio_tracks) { } // static variable for the currently active sequence -Sequence* olive::ActiveSequence = nullptr; +SequencePtr olive::ActiveSequence = nullptr; diff --git a/project/sequence.h b/project/sequence.h index 385c92c42..558ae3db2 100644 --- a/project/sequence.h +++ b/project/sequence.h @@ -71,7 +71,7 @@ using SequencePtr = std::shared_ptr; // static variable for the currently active sequence namespace olive { - extern Sequence* ActiveSequence; + extern SequencePtr ActiveSequence; } #endif // SEQUENCE_H diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index a48f80b88..c52f85f50 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -424,7 +424,7 @@ void SourcesCommon::clear_proxies_from_selected() { if (olive::ActiveSequence != nullptr) { // close all clips so we can delete any proxies requested to be deleted - close_active_clips(olive::ActiveSequence); + close_active_clips(olive::ActiveSequence.get()); } // delete proxies requested to be deleted diff --git a/project/undo.cpp b/project/undo.cpp index 5863e111f..7c2ca0374 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -140,7 +140,7 @@ void DeleteClipAction::doRedo() { } } -ChangeSequenceAction::ChangeSequenceAction(Sequence *s) { +ChangeSequenceAction::ChangeSequenceAction(SequencePtr s) { new_sequence = s; } @@ -514,7 +514,7 @@ void ReplaceMediaCommand::replace(QString& filename) { // close any clips currently using this media QVector all_sequences = panel_project->list_all_project_sequences(); for (int i=0;ito_sequence(); + Sequence* s = all_sequences.at(i)->to_sequence().get(); for (int j=0;jclips.size();j++) { ClipPtr c = s->clips.at(j); if (c != nullptr && c->media() == item && c->IsOpen()) { @@ -879,7 +879,7 @@ void SetSelectionsCommand::doRedo() { } } -EditSequenceCommand::EditSequenceCommand(Media* i, Sequence *s) { +EditSequenceCommand::EditSequenceCommand(Media* i, SequencePtr s) { item = i; seq = s; old_name = s->name; @@ -959,7 +959,7 @@ void CloseAllClipsCommand::doUndo() { } void CloseAllClipsCommand::doRedo() { - close_active_clips(olive::ActiveSequence); + close_active_clips(olive::ActiveSequence.get()); } UpdateFootageTooltip::UpdateFootageTooltip(Media *i) { @@ -1156,9 +1156,9 @@ void RefreshClips::doRedo() { // close any clips currently using this media QVector all_sequences = panel_project->list_all_project_sequences(); for (int i=0;ito_sequence(); + Sequence* s = all_sequences.at(i)->to_sequence().get(); for (int j=0;jclips.size();j++) { - ClipPtr c = s->clips.at(j); + Clip* c = s->clips.at(j).get(); if (c != nullptr && c->media() == media) { c->replaced = true; c->refresh(); @@ -1175,7 +1175,7 @@ void UpdateViewer::doRedo() { panel_sequence_viewer->viewer_widget->frame_update(); } -SetEffectData::SetEffectData(EffectPtr e, const QByteArray &s) { +SetEffectData::SetEffectData(Effect *e, const QByteArray &s) { effect = e; data = s; } diff --git a/project/undo.h b/project/undo.h index d2ba4d0dd..80840ba9c 100644 --- a/project/undo.h +++ b/project/undo.h @@ -115,12 +115,12 @@ private: class ChangeSequenceAction : public OliveAction { public: - ChangeSequenceAction(Sequence* s); + ChangeSequenceAction(SequencePtr s); virtual void doUndo() override; virtual void doRedo() override; private: - Sequence* old_sequence; - Sequence* new_sequence; + SequencePtr old_sequence; + SequencePtr new_sequence; }; class AddEffectCommand : public OliveAction { @@ -455,7 +455,7 @@ private: class EditSequenceCommand : public OliveAction { public: - EditSequenceCommand(Media *i, Sequence* s); + EditSequenceCommand(Media *i, SequencePtr s); virtual void doUndo() override; virtual void doRedo() override; void update(); @@ -468,7 +468,7 @@ public: int audio_layout; private: Media* item; - Sequence* seq; + SequencePtr seq; QString old_name; int old_width; @@ -626,11 +626,11 @@ public: class SetEffectData : public OliveAction { public: - SetEffectData(EffectPtr e, const QByteArray &s); + SetEffectData(Effect* e, const QByteArray &s); virtual void doUndo() override; virtual void doRedo() override; private: - EffectPtr effect; + Effect* effect; QByteArray data; QByteArray old_data; }; diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index deb51acf5..36286b355 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -51,8 +51,6 @@ namespace OCIO = OCIO_NAMESPACE; #include "panels/timeline.h" #include "panels/viewer.h" -const int kMaximumRetryCount = 10; - void full_blit() { glPushMatrix(); glLoadIdentity(); @@ -164,7 +162,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { if (!params.nests.isEmpty()) { for (int i=0;imedia()->to_sequence(); + s = params.nests.at(i)->media()->to_sequence().get(); playhead += params.nests.at(i)->clip_in(true) - params.nests.at(i)->timeline_in(true); playhead = rescale_frame_number(playhead, params.nests.at(i)->sequence->frame_rate, s->frame_rate); } diff --git a/ui/effectui.cpp b/ui/effectui.cpp index c8dcdc9d8..45d45a50c 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -42,7 +42,7 @@ EffectUI::EffectUI(Effect* e) : } } - connect(enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); + connect(enabled_check, SIGNAL(clicked(bool)), e, SLOT(FieldChanged())); } Effect *EffectUI::GetEffect() @@ -64,8 +64,11 @@ void EffectUI::show_context_menu(const QPoint& pos) { int index = c->IndexOfEffect(effect_); - menu.addAction(tr("Cu&t"), this, SIGNAL(CutRequested())); - menu.addAction(tr("&Copy"), this, SIGNAL(CopyRequested())); + QAction* cut_action = menu.addAction(tr("Cu&t")); + connect(cut_action, SIGNAL(triggered(bool)), this, SIGNAL(CutRequested())); + + QAction* copy_action = menu.addAction(tr("&Copy")); + connect(copy_action, SIGNAL(triggered(bool)), this, SIGNAL(CopyRequested())); olive::MenuHelper.create_effect_paste_action(&menu); diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 9319d4528..439581789 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -73,7 +73,9 @@ void LabelSlider::set_value(double v, bool userSet) { } setText(valueToString()); - if (userSet) emit valueChanged(); + if (userSet) { + emit valueChanged(internal_value); + } } } @@ -247,7 +249,7 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) { previous_value = drag_start_value; - emit valueChanged(); + emit valueChanged(internal_value); } else { diff --git a/ui/labelslider.h b/ui/labelslider.h index 5c203eaa6..a0ddc6a02 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -1,20 +1,20 @@ /*** - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . ***/ @@ -37,13 +37,13 @@ public: LabelSlider(QWidget* parent = nullptr); /** - * @brief Set the display frame rate - * - * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the - * timecode will be in. - * - * @param d - */ + * @brief Set the display frame rate + * + * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the + * timecode will be in. + * + * @param d + */ void set_frame_rate(double d); enum DisplayType { @@ -54,134 +54,134 @@ public: }; /** - * @brief Sets the way to display the value - * - * * `LABELSLIDER_NORMAL` - Shows the value as a normal number - * * `LABELSLIDER_FRAMENUMBER` - Shows the number as a timecode according to `config.timecode_view`. By default, - * will render hh:mm:ss:ff - * * `LABELSLIDER_PERCENT` - Shows the number as a percentage. 1.0 becomes "100%", 0.5 becomes 50%, etc. - * * `LABELSLIDER_DECIBLE` - Shows the number as a decibel. 1.0 becomes "0 dB", 2.0 becames roughly "6 dB", 0.5 - * becomes roughly "-6 dB", etc. - * - * @param type - * - * The display type to set to. - */ + * @brief Sets the way to display the value + * + * * `LABELSLIDER_NORMAL` - Shows the value as a normal number + * * `LABELSLIDER_FRAMENUMBER` - Shows the number as a timecode according to `config.timecode_view`. By default, + * will render hh:mm:ss:ff + * * `LABELSLIDER_PERCENT` - Shows the number as a percentage. 1.0 becomes "100%", 0.5 becomes 50%, etc. + * * `LABELSLIDER_DECIBLE` - Shows the number as a decibel. 1.0 becomes "0 dB", 2.0 becames roughly "6 dB", 0.5 + * becomes roughly "-6 dB", etc. + * + * @param type + * + * The display type to set to. + */ void set_display_type(const DisplayType& type); /** - * @brief Set the value - * @param v - * - * Value to set to. - * - * @param userSet - * - * **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The - * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and - * **FALSE** will not. - */ + * @brief Set the value + * @param v + * + * Value to set to. + * + * @param userSet + * + * **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The + * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and + * **FALSE** will not. + */ void set_value(double v, bool userSet); /** - * @brief Set the default value - * - * If a default value is set, alt+clicking the LabelSlider will return to the default value. - * - * @param v - * - * Value to set as default - */ + * @brief Set the default value + * + * If a default value is set, alt+clicking the LabelSlider will return to the default value. + * + * @param v + * + * Value to set as default + */ void set_default_value(double v); /** - * @brief Set the minimum value - * - * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than - * the minimum, it will automatically snap to the minimum. - * - * @param v - * - * Value to set as minimum - */ + * @brief Set the minimum value + * + * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than + * the minimum, it will automatically snap to the minimum. + * + * @param v + * + * Value to set as minimum + */ void set_minimum_value(double v); /** - * @brief Set the maximum value - * - * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than - * the maximum, it will automatically snap to the maximum. - * - * @param v - * - * Value to set as maximum - */ + * @brief Set the maximum value + * + * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than + * the maximum, it will automatically snap to the maximum. + * + * @param v + * + * Value to set as maximum + */ void set_maximum_value(double v); /** - * @brief Returns the internal value as a double - * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will - * return as 400%, and a timecode will return as a frame number. - */ + * @brief Returns the internal value as a double + * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will + * return as 400%, and a timecode will return as a frame number. + */ double value(); /** - * @brief Returns whether a value has been set or not - * - * If a value has been entered by any means (i.e. if set_value() was called), this will be **TRUE**. If set_value() - * has not been called and is_set() is **FALSE**, calling set_default_value() will automatically set the value - * to the default value WITHOUT changing the is_set() state (i.e. it will still be **FALSE** and calling - * set_default_value() again will change the current value again unless it's been changed through some other means - * in that time). - * - * @return **TRUE** if a value has been set, **FALSE** if not. - */ + * @brief Returns whether a value has been set or not + * + * If a value has been entered by any means (i.e. if set_value() was called), this will be **TRUE**. If set_value() + * has not been called and is_set() is **FALSE**, calling set_default_value() will automatically set the value + * to the default value WITHOUT changing the is_set() state (i.e. it will still be **FALSE** and calling + * set_default_value() again will change the current value again unless it's been changed through some other means + * in that time). + * + * @return **TRUE** if a value has been set, **FALSE** if not. + */ bool is_set(); /** - * @brief Returns whether the user is currently dragging - * @return **TRUE** if the user is dragging, **FALSE** if not. - */ + * @brief Returns whether the user is currently dragging + * @return **TRUE** if the user is dragging, **FALSE** if not. + */ bool is_dragging(); /** - * @brief Convert the internal value to a displayed string according to `display_type` - * @return The internal value as a string - */ + * @brief Convert the internal value to a displayed string according to `display_type` + * @return The internal value as a string + */ QString valueToString(); /** - * @brief Returns whatever value was set before the last set_value() - * - * For various reasons (largely undo capabilities) it is helpful to retrieve whatever the value was before the - * current one. If the user dragged the current value, this will return the value just before the user started - * dragging. - * - * @return The previous value - */ + * @brief Returns whatever value was set before the last set_value() + * + * For various reasons (largely undo capabilities) it is helpful to retrieve whatever the value was before the + * current one. If the user dragged the current value, this will return the value just before the user started + * dragging. + * + * @return The previous value + */ double getPreviousValue(); /** - * @brief Updates previous value - * - * Called internally to store the current value as the previous value in anticipation of an upcoming value change. - * Can also be called externally (mainly for dragged EffectGizmos) in anticipation of an external change. - */ + * @brief Updates previous value + * + * Called internally to store the current value as the previous value in anticipation of an upcoming value change. + * Can also be called externally (mainly for dragged EffectGizmos) in anticipation of an external change. + */ void set_previous_value(); /** - * @brief Set the display color - * @param c - * - * Color to set to - */ + * @brief Set the display color + * @param c + * + * Color to set to + */ void set_color(QString c = nullptr); /** - * @brief Set how many decimal places to show for a floating-point number - * - * Defaults to 1 - */ + * @brief Set how many decimal places to show for a floating-point number + * + * Defaults to 1 + */ int decimal_places; protected: void mousePressEvent(QMouseEvent *ev); @@ -210,13 +210,13 @@ private: double frame_rate; /** - * @brief Internal function to set the standard cursor (usually SizeHorCursor) - */ + * @brief Internal function to set the standard cursor (usually SizeHorCursor) + */ void set_default_cursor(); /** - * @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible) - */ + * @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible) + */ void set_active_cursor(); private slots: /** @@ -243,17 +243,17 @@ private slots: void prompt_for_value(); signals: /** - * @brief valueChanged signal - * - * Emitted if the value changed at it was instigated by the user. - */ - void valueChanged(); + * @brief valueChanged signal + * + * Emitted if the value changed at it was instigated by the user. + */ + void valueChanged(double d); /** - * @brief clicked signal - * - * Emitted if the user clicks on the LabelSlider in any way - */ + * @brief clicked signal + * + * Emitted if the user clicks on the LabelSlider in any way + */ void clicked(); }; diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index fbb2d3100..a9a4ea197 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -259,8 +259,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { } if (event->source() == panel_footage_viewer->viewer_widget) { - Sequence* proposed_seq = panel_footage_viewer->seq.get(); - if (proposed_seq != olive::ActiveSequence) { // don't allow nesting the same sequence + if (panel_footage_viewer->seq != olive::ActiveSequence) { // don't allow nesting the same sequence media_list.append(panel_footage_viewer->media); import_init = true; } @@ -302,7 +301,7 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { event->acceptProposedAction(); long entry_point; - Sequence* seq = olive::ActiveSequence; + Sequence* seq = olive::ActiveSequence.get(); if (seq == nullptr) { // if no sequence, we're going to create a new one using the clips as a reference @@ -486,13 +485,13 @@ void insert_clips(ComboAction* ca) { long ripple_length = (latest_new_point - earliest_new_point); - ripple_clips(ca, olive::ActiveSequence, earliest_new_point, ripple_length, ignore_clips); + ripple_clips(ca, olive::ActiveSequence.get(), earliest_new_point, ripple_length, ignore_clips); if (ripple_old_point) { // works for moving later clips earlier but not earlier to later long second_ripple_length = (earliest_old_point - latest_old_point); - ripple_clips(ca, olive::ActiveSequence, latest_old_point, second_ripple_length, ignore_clips); + ripple_clips(ca, olive::ActiveSequence.get(), latest_old_point, second_ripple_length, ignore_clips); if (earliest_old_point < earliest_new_point) { for (int i=0;ighosts.size();i++) { @@ -515,7 +514,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { ComboAction* ca = new ComboAction(); - Sequence* s = olive::ActiveSequence; + Sequence* s = olive::ActiveSequence.get(); // if we're dropping into nothing, create a new sequences based on the clip being dragged if (s == nullptr) { @@ -998,7 +997,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { panel_sequence_viewer->cue_recording(qMin(g.in, g.out), qMax(g.in, g.out), g.track); panel_timeline->creating = false; } else if (g.in != g.out) { - ClipPtr c = std::make_shared(olive::ActiveSequence); + ClipPtr c = std::make_shared(olive::ActiveSequence.get()); c->set_media(nullptr, 0); c->set_timeline_in(qMin(g.in, g.out)); c->set_timeline_out(qMax(g.in, g.out)); @@ -1020,7 +1019,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { QVector add; add.append(c); - ca->append(new AddClipCommand(olive::ActiveSequence, add)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), add)); if (c->track() < 0 && olive::CurrentConfig.add_default_effects_to_clips) { // default video effects (before custom effects) @@ -1141,7 +1140,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (panel_timeline->trim_type == TRIM_OUT) ripple_length = -ripple_length; // finally, ripple everything - ripple_clips(ca, olive::ActiveSequence, ripple_point, ripple_length, ignore_clips); + ripple_clips(ca, olive::ActiveSequence.get(), ripple_point, ripple_length, ignore_clips); } if (panel_timeline->tool == TIMELINE_TOOL_POINTER @@ -1157,7 +1156,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (g.old_in != g.in || g.old_out != g.out || g.track != g.old_track || g.clip_in != g.old_clip_in) { // create copy of clip - ClipPtr c(olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence)); + ClipPtr c = olive::ActiveSequence->clips.at(g.clip)->copy(olive::ActiveSequence.get()); c->set_timeline_in(g.in); c->set_timeline_out(g.out); @@ -1184,7 +1183,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { panel_timeline->relink_clips_using_ids(old_clips, new_clips); // add them - ca->append(new AddClipCommand(olive::ActiveSequence, new_clips)); + ca->append(new AddClipCommand(olive::ActiveSequence.get(), new_clips)); } @@ -2342,7 +2341,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } // store selections - selection_command = new SetSelectionsCommand(olive::ActiveSequence); + selection_command = new SetSelectionsCommand(olive::ActiveSequence.get()); selection_command->old_data = olive::ActiveSequence->selections; // ready to start moving clips @@ -2953,7 +2952,6 @@ void TimelineWidget::paintEvent(QPaintEvent*) { if (clip->media() != nullptr && clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) { bool draw_checkerboard = false; QRect checkerboard_rect(clip_rect); - Footage* m = clip->media()->to_footage(); FootageStream* ms = clip->media_stream(); if (ms == nullptr) { draw_checkerboard = true; diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 0ac1d6dfa..0db17dc66 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -311,7 +311,7 @@ void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) { drag_start_x = event->pos().x(); drag_start_y = event->pos().y(); - gizmos->field_changed(); + gizmos->FieldChanged(); } } From 928adde78a36eeab020bb52a613ee0dad814cc54 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 00:22:19 +1100 Subject: [PATCH 05/56] removed main thread pass-off when loading --- io/loadthread.cpp | 130 +++++++++++++++++----------------------------- io/loadthread.h | 16 +----- 2 files changed, 49 insertions(+), 97 deletions(-) diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 5aab007ea..891b930aa 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -47,11 +47,6 @@ LoadThread::LoadThread(const QString& filename, bool autorecovery, bool clear) : connect(this, SIGNAL(success()), this, SLOT(success_func()), Qt::QueuedConnection); connect(this, SIGNAL(error()), this, SLOT(error_func()), Qt::QueuedConnection); - connect(this, - SIGNAL(start_create_effect_ui(QXmlStreamReader*, Clip*, int, const QString*, const EffectMeta*, long, bool)), - this, - SLOT(create_effect_ui(QXmlStreamReader*, Clip*, int, const QString*, const EffectMeta*, long, bool)), - Qt::QueuedConnection); connect(this, SIGNAL(start_question(const QString&, const QString &, int)), this, @@ -135,9 +130,34 @@ void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) { type = kTransitionNone; } - // effect UI creation has to occur in the main thread, see an explanation in create_effect_ui() - emit start_create_effect_ui(&stream, c, type, &effect_name, meta, effect_length, effect_enabled); - waitCond.wait(&mutex); + // effect construction + if (cancelled_) return; + if (type == kTransitionNone) { + if (meta == nullptr) { + // create void effect + EffectPtr ve(new VoidEffect(c, effect_name)); + ve->SetEnabled(effect_enabled); + ve->load(stream); + c->effects.append(ve); + } else { + EffectPtr e(Effect::Create(c, meta)); + e->SetEnabled(effect_enabled); + e->load(stream); + + c->effects.append(e); + } + } else { + TransitionPtr t = Transition::Create(c, nullptr, meta); + if (effect_length > -1) t->set_length(effect_length); + t->SetEnabled(effect_enabled); + t->load(stream); + + if (type == kTransitionOpening) { + c->opening_transition = t; + } else { + c->closing_transition = t; + } + } } void LoadThread::read_next(QXmlStreamReader &stream) { @@ -157,6 +177,16 @@ void LoadThread::update_current_element_count(QXmlStreamReader &stream) { } } +void LoadThread::show_message(const QString& title, const QString& body, int buttons) +{ + emit start_question( + title, + body, + buttons + ); + waitCond.wait(&mutex); +} + bool LoadThread::is_element(QXmlStreamReader &stream) { return stream.isStartElement() && (stream.name() == "folder" @@ -204,12 +234,11 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { if (type == LOAD_TYPE_VERSION) { proj_version = stream.readElementText().toInt(); if (proj_version < olive::kMinimumSaveVersion || proj_version > olive::kSaveVersion) { - emit start_question( - tr("Version Mismatch"), - tr("This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway?"), - QMessageBox::Yes | QMessageBox::No + show_message( + tr("Version Mismatch"), + tr("This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway?"), + QMessageBox::Yes | QMessageBox::No ); - waitCond.wait(&mutex); if (question_btn == QMessageBox::No) { show_err = false; return false; @@ -398,7 +427,8 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { s->markers.append(m); } else if (stream.name() == "clip" && stream.isStartElement()) { int media_type = -1; - int media_id, stream_id; + int media_id = -1; + int stream_id = -1; ClipPtr c = std::make_shared(s.get()); @@ -455,7 +485,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { // set media and media stream switch (media_type) { case MEDIA_TYPE_FOOTAGE: - if (media_id >= 0) { + if (media_id >= 0 && stream_id >= 0) { for (int j=0;jto_footage(); if (m->save_id == media_id) { @@ -528,12 +558,12 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { correct_clip->linked.removeAt(j); j--; - emit start_question( + show_message( tr("Invalid Clip Link"), tr("This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it?"), QMessageBox::Yes | QMessageBox::No ); - waitCond.wait(&mutex); + if (question_btn == QMessageBox::No) { s.reset(); return false; @@ -745,69 +775,3 @@ void LoadThread::success_func() { olive::Global->set_sequence(open_seq); } } - -void LoadThread::create_effect_ui( - QXmlStreamReader* stream, - Clip* c, - int type, - const QString* effect_name, - const EffectMeta* meta, - long effect_length, - bool effect_enabled) -{ - /* This is extremely hacky - prepare yourself. - * - * When moving project loading to a separate thread, it was soon discovered - * that effects wouldn't load correctly anymore. They were actually still - * "functional", but there were no controls appearing in EffectControls. - * - * Turns out since Effect creates its UI in its constructor, the UI was - * created in this thread rather than the main GUI thread, which is a big - * no-no. Unfortunately the design of Effect does not separate UI and data, - * so having the UI set up was integral to creating annd loading the effect. - * - * Therefore, rather than rewrite the class (I just rewrote QTreeWidget to - * QTreeView with a custom model/item so I'm exhausted), for - * quick-n-dirty-ness, I made LoadThread offload the effect creation to the - * main thread (and since the effect loads data from the same XML stream, - * the LoadThread has to wait for the effect to finish before it can - * continue. - * - * Sorry. I'll fix it one day. - */ - - // lock mutex - ensures the load thread is suspended while this happens - mutex.lock(); - - if (cancelled_) return; - if (type == kTransitionNone) { - if (meta == nullptr) { - // create void effect - EffectPtr ve(new VoidEffect(c, *effect_name)); - ve->SetEnabled(effect_enabled); - ve->load(*stream); - c->effects.append(ve); - } else { - EffectPtr e(Effect::Create(c, meta)); - e->SetEnabled(effect_enabled); - e->load(*stream); - - c->effects.append(e); - } - } else { - TransitionPtr t = Transition::Create(c, nullptr, meta); - if (effect_length > -1) t->set_length(effect_length); - t->SetEnabled(effect_enabled); - t->load(*stream); - - if (type == kTransitionOpening) { - c->opening_transition = t; - } else { - c->closing_transition = t; - } - } - - mutex.unlock(); - - waitCond.wakeAll(); -} diff --git a/io/loadthread.h b/io/loadthread.h index 14b92e7b2..22da99ded 100644 --- a/io/loadthread.h +++ b/io/loadthread.h @@ -41,25 +41,11 @@ signals: void start_question(const QString &title, const QString &text, int buttons); void success(); void error(); - void start_create_effect_ui(QXmlStreamReader* stream, - Clip* c, - int type, - const QString *effect_name, - const EffectMeta* meta, - long effect_length, - bool effect_enabled); void report_progress(int p); private slots: void question_func(const QString &title, const QString &text, int buttons); void error_func(); void success_func(); - void create_effect_ui(QXmlStreamReader* stream, - Clip* c, - int type, - const QString *effect_name, - const EffectMeta* meta, - long effect_length, - bool effect_enabled); private: bool autorecovery_; bool clear_; @@ -72,6 +58,8 @@ private: void read_next_start_element(QXmlStreamReader& stream); void update_current_element_count(QXmlStreamReader& stream); + void show_message(const QString& title, const QString& body, int buttons); + SequencePtr open_seq; QVector loaded_media_items; QDir proj_dir; From 101b728c19d6ec9c28f37239b54d71beaa63ffa1 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 00:23:47 +1100 Subject: [PATCH 06/56] formatting improvement --- io/loadthread.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 891b930aa..8c66718c2 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -46,7 +46,9 @@ LoadThread::LoadThread(const QString& filename, bool autorecovery, bool clear) : connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); connect(this, SIGNAL(success()), this, SLOT(success_func()), Qt::QueuedConnection); + connect(this, SIGNAL(error()), this, SLOT(error_func()), Qt::QueuedConnection); + connect(this, SIGNAL(start_question(const QString&, const QString &, int)), this, From db29e9e576fc4da75ff855be4f91d6620d962fa9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 00:35:51 +1100 Subject: [PATCH 07/56] ensure effects are in the main thread --- io/loadthread.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 8c66718c2..0a7fd561a 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -140,18 +140,20 @@ void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) { EffectPtr ve(new VoidEffect(c, effect_name)); ve->SetEnabled(effect_enabled); ve->load(stream); + ve->moveToThread(QApplication::instance()->thread()); c->effects.append(ve); } else { EffectPtr e(Effect::Create(c, meta)); e->SetEnabled(effect_enabled); e->load(stream); - + e->moveToThread(QApplication::instance()->thread()); c->effects.append(e); } } else { TransitionPtr t = Transition::Create(c, nullptr, meta); if (effect_length > -1) t->set_length(effect_length); t->SetEnabled(effect_enabled); + t->moveToThread(QApplication::instance()->thread()); t->load(stream); if (type == kTransitionOpening) { From 9522432112d9107208255ecd5e2e37e195c5f31c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 00:36:05 +1100 Subject: [PATCH 08/56] indentation fix --- effects/internal/voideffect.h | 14 +++++++------- ui/mediaiconservice.cpp | 8 ++++---- ui/mediaiconservice.h | 32 ++++++++++++++++---------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/effects/internal/voideffect.h b/effects/internal/voideffect.h index 210b8bed0..7d524302f 100644 --- a/effects/internal/voideffect.h +++ b/effects/internal/voideffect.h @@ -30,16 +30,16 @@ #include "project/effect.h" class VoidEffect : public Effect { - Q_OBJECT + Q_OBJECT public: - VoidEffect(Clip* c, const QString& n); + VoidEffect(Clip* c, const QString& n); - virtual EffectPtr copy(Clip* c) override; - virtual void load(QXmlStreamReader &stream) override; - virtual void save(QXmlStreamWriter &stream) override; + virtual EffectPtr copy(Clip* c) override; + virtual void load(QXmlStreamReader &stream) override; + virtual void save(QXmlStreamWriter &stream) override; private: - QByteArray bytes; - EffectMeta void_meta; + QByteArray bytes; + EffectMeta void_meta; }; #endif // VOIDEFFECT_H diff --git a/ui/mediaiconservice.cpp b/ui/mediaiconservice.cpp index 64d69ca99..90d67e024 100644 --- a/ui/mediaiconservice.cpp +++ b/ui/mediaiconservice.cpp @@ -40,11 +40,11 @@ MediaIconService::MediaIconService() { void MediaIconService::SetMediaIcon(Media *media, int icon_type) { // if this icon is already part of the throbber animation loop, remove it if (throbber_items_.contains(media)) { -// throbber_lock_.lock(); + // throbber_lock_.lock(); throbber_items_.removeAll(media); -// throbber_lock_.unlock(); + // throbber_lock_.unlock(); // if we aren't animating anything, no need to run the timer for now if (throbber_items_.empty()) { @@ -90,13 +90,13 @@ void MediaIconService::AnimationUpdate() { QIcon throbber_ico = QIcon(throbber_pixmap_.copy(kThrobberSize*throbber_animation_frame_, 0, kThrobberSize, kThrobberSize)); -// throbber_lock_.lock(); + // throbber_lock_.lock(); for (int i=0;i throbber_items_; - QTimer throbber_animator_; - QPixmap throbber_pixmap_; - QMutex throbber_lock_; + int throbber_animation_frame_; + QVector throbber_items_; + QTimer throbber_animator_; + QPixmap throbber_pixmap_; + QMutex throbber_lock_; }; namespace olive { - extern std::unique_ptr media_icon_service; +extern std::unique_ptr media_icon_service; } #endif // MEDIAICONSERVICE_H From d6e62c5ef9c5c7f851eae806fcb20b2d78133c10 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 00:39:57 +1100 Subject: [PATCH 09/56] forced thread safety on media throbber --- io/loadthread.cpp | 7 ++++++- ui/mediaiconservice.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 0a7fd561a..b8dbf9534 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -140,22 +140,27 @@ void LoadThread::load_effect(QXmlStreamReader& stream, Clip* c) { EffectPtr ve(new VoidEffect(c, effect_name)); ve->SetEnabled(effect_enabled); ve->load(stream); + ve->moveToThread(QApplication::instance()->thread()); + c->effects.append(ve); } else { EffectPtr e(Effect::Create(c, meta)); e->SetEnabled(effect_enabled); e->load(stream); + e->moveToThread(QApplication::instance()->thread()); + c->effects.append(e); } } else { TransitionPtr t = Transition::Create(c, nullptr, meta); if (effect_length > -1) t->set_length(effect_length); t->SetEnabled(effect_enabled); - t->moveToThread(QApplication::instance()->thread()); t->load(stream); + t->moveToThread(QApplication::instance()->thread()); + if (type == kTransitionOpening) { c->opening_transition = t; } else { diff --git a/ui/mediaiconservice.cpp b/ui/mediaiconservice.cpp index 90d67e024..9563c54e1 100644 --- a/ui/mediaiconservice.cpp +++ b/ui/mediaiconservice.cpp @@ -40,11 +40,11 @@ MediaIconService::MediaIconService() { void MediaIconService::SetMediaIcon(Media *media, int icon_type) { // if this icon is already part of the throbber animation loop, remove it if (throbber_items_.contains(media)) { - // throbber_lock_.lock(); + throbber_lock_.lock(); throbber_items_.removeAll(media); - // throbber_lock_.unlock(); + throbber_lock_.unlock(); // if we aren't animating anything, no need to run the timer for now if (throbber_items_.empty()) { @@ -90,13 +90,13 @@ void MediaIconService::AnimationUpdate() { QIcon throbber_ico = QIcon(throbber_pixmap_.copy(kThrobberSize*throbber_animation_frame_, 0, kThrobberSize, kThrobberSize)); - // throbber_lock_.lock(); + throbber_lock_.lock(); for (int i=0;i Date: Wed, 13 Mar 2019 00:45:18 +1100 Subject: [PATCH 10/56] reimplemented UI for combobox --- project/effectfields/combofield.cpp | 22 +++++++++++++++++++++- project/effectfields/combofield.h | 7 ++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/project/effectfields/combofield.cpp b/project/effectfields/combofield.cpp index 301b1f8f2..ff4a1a164 100644 --- a/project/effectfields/combofield.cpp +++ b/project/effectfields/combofield.cpp @@ -1,5 +1,7 @@ #include "combofield.h" +#include + ComboField::ComboField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_COMBO) {} @@ -9,7 +11,25 @@ void ComboField::AddItem(const QString &text, const QVariant &data) ComboFieldItem item; item.name = text; - item.data.append(data); + item.data = data; items_.append(item); } + +QWidget *ComboField::CreateWidget() +{ + QComboBox* cb = new QComboBox(); + + for (int i=0;iaddItem(items_.at(i).name); + } + + connect(cb, SIGNAL(activated(int)), this, SLOT(UpdateFromWidget(int))); + + return cb; +} + +void ComboField::UpdateFromWidget(int index) +{ + SetValueAt(Now(), items_.at(index).data); +} diff --git a/project/effectfields/combofield.h b/project/effectfields/combofield.h index 26afd90b3..c886a0172 100644 --- a/project/effectfields/combofield.h +++ b/project/effectfields/combofield.h @@ -5,7 +5,7 @@ struct ComboFieldItem { QString name; - QVector data; + QVariant data; }; class ComboField : public EffectField @@ -16,11 +16,16 @@ public: void AddItem(const QString& text, const QVariant& data); + virtual QWidget *CreateWidget() override; + signals: void IndexChanged(int i); private: QVector items_; + +private slots: + void UpdateFromWidget(int index); }; #endif // COMBOFIELD_H From d01e868d607a141c8a52e6bff2e5621ca5d1e9e0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 01:10:17 +1100 Subject: [PATCH 11/56] reimplemented text field --- dialogs/preferencesdialog.cpp | 16 +++++++++++++--- project/effectfields/stringfield.cpp | 26 ++++++++++++++++++++++++++ project/effectfields/stringfield.h | 4 ++++ ui/texteditex.cpp | 7 +++++++ ui/texteditex.h | 21 +++------------------ 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 78312b4c2..859ae57db 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -24,6 +24,7 @@ #include "io/config.h" #include "io/path.h" #include "rendering/audio.h" +#include "panels/panels.h" #include "mainwindow.h" #include @@ -74,7 +75,7 @@ QString KeySequenceEditor::export_shortcut() { if (ks != action->property("default")) { return action->property("id").toString() + "\t" + keySequence().toString(); } - return 0; + return nullptr; } PreferencesDialog::PreferencesDialog(QWidget *parent) : @@ -173,6 +174,7 @@ void PreferencesDialog::save() { bool restart_after_saving = false; bool reinit_audio = false; bool reload_language = false; + bool reload_effects = false; // Validate whether the specified CSS file exists if (!custom_css_fn->text().isEmpty() && !QFileInfo::exists(custom_css_fn->text())) { @@ -184,9 +186,13 @@ void PreferencesDialog::save() { return; } + // Validate whether the effects panel should refresh itself + if (olive::CurrentConfig.effect_textbox_lines != effect_textbox_lines_field->value()) { + reload_effects = true; + } + // Check if any settings will require a restart of Olive - if (olive::CurrentConfig.effect_textbox_lines != effect_textbox_lines_field->value() - || olive::CurrentConfig.use_software_fallback != use_software_fallbacks_checkbox->isChecked() + if (olive::CurrentConfig.use_software_fallback != use_software_fallbacks_checkbox->isChecked() || olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) { @@ -290,6 +296,10 @@ void PreferencesDialog::save() { init_audio(); } + if (reload_effects) { + panel_effect_controls->Reload(); + } + // reload language file if it changed if (reload_language) { olive::Global->load_translation_from_config(); diff --git a/project/effectfields/stringfield.cpp b/project/effectfields/stringfield.cpp index 609a62362..322f40f6f 100644 --- a/project/effectfields/stringfield.cpp +++ b/project/effectfields/stringfield.cpp @@ -1,5 +1,10 @@ #include "stringfield.h" +#include + +#include "ui/texteditex.h" +#include "io/config.h" + StringField::StringField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_STRING) { @@ -10,3 +15,24 @@ QString StringField::GetStringAt(double timecode) { return GetValueAt(timecode).toString(); } + +QWidget *StringField::CreateWidget() +{ + TextEditEx* text_edit = new TextEditEx(); + + text_edit->setUndoRedoEnabled(true); + + // the "2" looks like a magic number, but it's just one pixel on the top and the bottom + text_edit->setFixedHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + + text_edit->document()->documentMargin() + + text_edit->document()->documentMargin() + 2)); + + connect(text_edit, SIGNAL(textModified(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); + + return text_edit; +} + +void StringField::UpdateFromWidget(const QString &s) +{ + SetValueAt(Now(), s); +} diff --git a/project/effectfields/stringfield.h b/project/effectfields/stringfield.h index a7ca70668..043dbbb67 100644 --- a/project/effectfields/stringfield.h +++ b/project/effectfields/stringfield.h @@ -10,6 +10,10 @@ public: StringField(EffectRow* parent, const QString& id); QString GetStringAt(double timecode); + + virtual QWidget *CreateWidget() override; +private slots: + void UpdateFromWidget(const QString& b); }; #endif // STRINGFIELD_H diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp index f56bcf1cc..e4c525dd4 100644 --- a/ui/texteditex.cpp +++ b/ui/texteditex.cpp @@ -72,6 +72,8 @@ TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) { setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); + + connect(this, SIGNAL(textChanged()), this, SLOT(queue_text_modified())); } void TextEditEx::text_edit_menu() { @@ -90,3 +92,8 @@ void TextEditEx::open_text_edit() { setHtml(result); } } + +void TextEditEx::queue_text_modified() +{ + emit textModified(toHtml()); +} diff --git a/ui/texteditex.h b/ui/texteditex.h index aca586034..20d3d08f9 100644 --- a/ui/texteditex.h +++ b/ui/texteditex.h @@ -23,31 +23,16 @@ #include -/* class TextEditEx : public QTextEdit { Q_OBJECT public: - TextEditEx(QWidget* parent = 0); - void setPlainTextEx(const QString &text); - const QString& getPreviousValue(); - const QString& getPlainTextEx(); + TextEditEx(QWidget* parent = nullptr); signals: - void updateSelf(); -private slots: - void updateInternals(); - void updateText(); -private: - QString previousText; - QString text; -}; -*/ - -class TextEditEx : public QTextEdit { -public: - TextEditEx(QWidget* parent); + void textModified(const QString& s); private slots: void text_edit_menu(); void open_text_edit(); + void queue_text_modified(); }; #endif // TEXTEDITEX_H From b7b9c866a8695eabdaa3ae599e34ee82a9f0a673 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 01:18:38 +1100 Subject: [PATCH 12/56] started text controls in texteditdialog --- dialogs/texteditdialog.cpp | 48 +++++++++++++++++++++++++++----------- dialogs/texteditdialog.h | 14 +++++------ 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/dialogs/texteditdialog.cpp b/dialogs/texteditdialog.cpp index 2dcc158af..de9328209 100644 --- a/dialogs/texteditdialog.cpp +++ b/dialogs/texteditdialog.cpp @@ -22,33 +22,53 @@ #include #include +#include TextEditDialog::TextEditDialog(QWidget *parent, const QString &s) : - QDialog(parent) + QDialog(parent) { - setWindowTitle(tr("Edit Text")); + setWindowTitle(tr("Edit Text")); - QVBoxLayout* layout = new QVBoxLayout(this); + QVBoxLayout* layout = new QVBoxLayout(this); - textEdit = new QPlainTextEdit(this); - textEdit->setPlainText(s); - layout->addWidget(textEdit); + QHBoxLayout* toolbar = new QHBoxLayout(); - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - layout->addWidget(buttons); - connect(buttons, SIGNAL(accepted()), this, SLOT(save())); - connect(buttons, SIGNAL(rejected()), this, SLOT(cancel())); + QPushButton* italic_button = new QPushButton("I"); + italic_button->setCheckable(true); + toolbar->addWidget(italic_button); + + QPushButton* underline_button = new QPushButton("U"); + underline_button->setCheckable(true); + toolbar->addWidget(underline_button); + + toolbar->addStretch(); + + layout->addLayout(toolbar); + + textEdit = new QTextEdit(this); + textEdit->setHtml(s); + layout->addWidget(textEdit); + + // Connect buttons to the text field + connect(italic_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontItalic(bool))); + connect(underline_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontUnderline(bool))); + + // Create dialog buttons at the bottom + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + layout->addWidget(buttons); + connect(buttons, SIGNAL(accepted()), this, SLOT(save())); + connect(buttons, SIGNAL(rejected()), this, SLOT(cancel())); } const QString& TextEditDialog::get_string() { - return result_str; + return result_str; } void TextEditDialog::save() { - result_str = textEdit->toPlainText(); - accept(); + result_str = textEdit->toHtml(); + accept(); } void TextEditDialog::cancel() { - reject(); + reject(); } diff --git a/dialogs/texteditdialog.h b/dialogs/texteditdialog.h index 6e7b29567..28a682d90 100644 --- a/dialogs/texteditdialog.h +++ b/dialogs/texteditdialog.h @@ -25,16 +25,16 @@ #include class TextEditDialog : public QDialog { - Q_OBJECT + Q_OBJECT public: - TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr); - const QString& get_string(); + TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr); + const QString& get_string(); private slots: - void save(); - void cancel(); + void save(); + void cancel(); private: - QString result_str; - QPlainTextEdit* textEdit; + QString result_str; + QTextEdit* textEdit; }; #endif // TEXTEDITDIALOG_H From e82b0e4914f7115a0a030432e45f3c17318cd77f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 08:43:46 +1100 Subject: [PATCH 13/56] implemented all field UIs --- effects/internal/texteffect.cpp | 4 +- effects/internal/texteffect.h | 2 +- effects/internal/vsthost.cpp | 36 ++++++++------ effects/internal/vsthost.h | 1 + project/effectfields/buttonfield.cpp | 26 +++++++++-- project/effectfields/buttonfield.h | 8 ++++ project/effectfields/colorfield.cpp | 17 +++++++ project/effectfields/colorfield.h | 4 ++ project/effectfields/combofield.cpp | 1 + project/effectfields/doublefield.cpp | 2 + project/effectfields/effectfield.h | 1 + project/effectfields/filefield.cpp | 17 +++++++ project/effectfields/filefield.h | 4 ++ project/effectfields/fontfield.cpp | 22 +++++++++ project/effectfields/fontfield.h | 6 +++ project/effectfields/labelfield.cpp | 15 +++++- project/effectfields/labelfield.h | 4 ++ project/effectfields/stringfield.cpp | 2 + project/undo.cpp | 3 -- ui/colorbutton.cpp | 40 ++++++++-------- ui/colorbutton.h | 32 ++++++------- ui/comboboxex.h | 18 +++---- ui/embeddedfilechooser.cpp | 70 ++++++++++++++-------------- ui/embeddedfilechooser.h | 22 ++++----- ui/fontcombobox.cpp | 14 +++--- ui/fontcombobox.h | 16 +++---- 26 files changed, 256 insertions(+), 131 deletions(-) diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index ff0b13c02..59b80b929 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -138,8 +138,8 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : outline_enable(false); shadow_enable(false); - connect(shadow_bool, SIGNAL(toggled(bool)), this, SLOT(shadow_enable(bool))); - connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool))); + connect(shadow_bool, SIGNAL(Toggled(bool)), this, SLOT(shadow_enable(bool))); + connect(outline_bool, SIGNAL(Toggled(bool)), this, SLOT(outline_enable(bool))); vertPath = "common.vert"; fragPath = "dropshadow.frag"; diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h index c3d7734a6..e389a5873 100644 --- a/effects/internal/texteffect.h +++ b/effects/internal/texteffect.h @@ -29,7 +29,7 @@ class TextEffect : public Effect { Q_OBJECT public: - TextEffect(Clip* c, const EffectMeta *em); + TextEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); StringField* text_val; diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index c29f9c550..f831abc4e 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -256,7 +256,22 @@ void VSTHost::processAudio(long numFrames) { plugin->processReplacing(plugin, inputs, outputs, numFrames); } -VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) { +void VSTHost::CreateDialogIfNull() +{ + if (dialog == nullptr) { + dialog = new QDialog(olive::MainWindow); + dialog->setWindowTitle(tr("VST Plugin")); + dialog->setAttribute(Qt::WA_NativeWindow, true); + dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint); + connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button())); + } +} + +VSTHost::VSTHost(Clip* c, const EffectMeta *em) : + Effect(c, em), + plugin(nullptr), + dialog(nullptr) +{ plugin = nullptr; inputs = new float* [CHANNEL_COUNT]; @@ -268,21 +283,14 @@ VSTHost::VSTHost(Clip* c, const EffectMeta *em) : Effect(c, em) { EffectRow* file_row = new EffectRow(this, tr("Plugin"), true, false); file_field = new FileField(file_row, "filename"); - connect(file_field, SIGNAL(changed()), this, SLOT(change_plugin())); + connect(file_field, SIGNAL(Changed()), this, SLOT(change_plugin())); EffectRow* interface_row = new EffectRow(this, tr("Interface"), false, false); - show_interface_btn = new ButtonField(interface_row, tr("Show")); show_interface_btn->SetCheckable(true); show_interface_btn->SetEnabled(false); - connect(show_interface_btn, SIGNAL(toggled(bool)), this, SLOT(show_interface(bool))); - - dialog = new QDialog(olive::MainWindow); - dialog->setWindowTitle(tr("VST Plugin")); - dialog->setAttribute(Qt::WA_NativeWindow, true); - dialog->setWindowFlags(dialog->windowFlags() | Qt::MSWindowsFixedSizeDialogHint); - connect(dialog, SIGNAL(finished(int)), this, SLOT(uncheck_show_button())); + connect(show_interface_btn, SIGNAL(Toggled(bool)), this, SLOT(show_interface(bool))); } VSTHost::~VSTHost() { @@ -294,9 +302,6 @@ VSTHost::~VSTHost() { delete [] inputs; freePlugin(); - - delete show_interface_btn; - delete dialog; } void VSTHost::process_audio(double, double, quint8* samples, int nb_bytes, int) { @@ -358,6 +363,7 @@ void VSTHost::save(QXmlStreamWriter &stream) { } void VSTHost::show_interface(bool show) { + CreateDialogIfNull(); dialog->setVisible(show); if (show) { @@ -383,9 +389,13 @@ void VSTHost::change_plugin() { if (plugin != nullptr) { if (configurePluginCallbacks()) { startPlugin(); + VSTRect* eRect = nullptr; plugin->dispatcher(plugin, effEditGetRect, 0, 0, &eRect, 0); + + CreateDialogIfNull(); dialog->setFixedSize(eRect->right - eRect->left, eRect->bottom - eRect->top); + } else { #ifdef __APPLE__ CFBundleUnloadExecutable(bundle); diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 5ac307139..5e30312ba 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -62,6 +62,7 @@ private: void suspendPlugin(); bool canPluginDo(char *canDoString); void processAudio(long numFrames); + void CreateDialogIfNull(); float** inputs; float** outputs; QDialog* dialog; diff --git a/project/effectfields/buttonfield.cpp b/project/effectfields/buttonfield.cpp index 28865d62f..57845808f 100644 --- a/project/effectfields/buttonfield.cpp +++ b/project/effectfields/buttonfield.cpp @@ -1,10 +1,11 @@ #include "buttonfield.h" +#include + ButtonField::ButtonField(EffectRow *parent, const QString &string) : - EffectField(parent, nullptr, EFFECT_FIELD_UI) -{ - SetValueAt(0, string); -} + EffectField(parent, nullptr, EFFECT_FIELD_UI), + button_text_(string) +{} void ButtonField::SetCheckable(bool c) { @@ -16,3 +17,20 @@ void ButtonField::SetChecked(bool c) checked_ = c; emit CheckedChanged(c); } + +QWidget *ButtonField::CreateWidget() +{ + QPushButton* button = new QPushButton(); + + button->setCheckable(checkable_); + button->setEnabled(IsEnabled()); + button->setText(button_text_); + + connect(this, SIGNAL(CheckedChanged(bool)), button, SLOT(setChecked(bool))); + connect(this, SIGNAL(EnabledChanged(bool)), button, SLOT(setEnabled(bool))); + connect(button, SIGNAL(clicked(bool)), this, SIGNAL(Clicked())); + connect(button, SIGNAL(toggled(bool)), this, SLOT(SetChecked(bool))); + connect(button, SIGNAL(toggled(bool)), this, SIGNAL(Toggled(bool))); + + return button; +} diff --git a/project/effectfields/buttonfield.h b/project/effectfields/buttonfield.h index eb108427c..71e77f1ac 100644 --- a/project/effectfields/buttonfield.h +++ b/project/effectfields/buttonfield.h @@ -10,12 +10,20 @@ public: ButtonField(EffectRow* parent, const QString& string); void SetCheckable(bool c); + virtual QWidget* CreateWidget() override; + +public slots: void SetChecked(bool c); + signals: void CheckedChanged(bool); + void Toggled(bool); + private: bool checkable_; bool checked_; + + QString button_text_; }; #endif // BUTTONFIELD_H diff --git a/project/effectfields/colorfield.cpp b/project/effectfields/colorfield.cpp index 435c79ddc..865505dd2 100644 --- a/project/effectfields/colorfield.cpp +++ b/project/effectfields/colorfield.cpp @@ -2,6 +2,8 @@ #include +#include "ui/colorbutton.h" + ColorField::ColorField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_COLOR) {} @@ -11,6 +13,16 @@ QColor ColorField::GetColorAt(double timecode) return GetValueAt(timecode).value(); } +QWidget *ColorField::CreateWidget() +{ + ColorButton* cb = new ColorButton(); + + connect(cb, SIGNAL(color_changed(const QColor &)), this, SLOT(UpdateFromWidget(const QColor &))); + connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); + + return cb; +} + QVariant ColorField::ConvertStringToValue(const QString &s) { return QColor(s); @@ -20,3 +32,8 @@ QString ColorField::ConvertValueToString(const QVariant &v) { return v.value().name(); } + +void ColorField::UpdateFromWidget(const QColor& c) +{ + SetValueAt(Now(), c); +} diff --git a/project/effectfields/colorfield.h b/project/effectfields/colorfield.h index 26f668c65..f4ef25020 100644 --- a/project/effectfields/colorfield.h +++ b/project/effectfields/colorfield.h @@ -11,8 +11,12 @@ public: QColor GetColorAt(double timecode); + virtual QWidget* CreateWidget() override; + virtual QVariant ConvertStringToValue(const QString& s) override; virtual QString ConvertValueToString(const QVariant& v) override; +private slots: + void UpdateFromWidget(const QColor &c); }; #endif // COLORFIELD_H diff --git a/project/effectfields/combofield.cpp b/project/effectfields/combofield.cpp index ff4a1a164..46576aa7a 100644 --- a/project/effectfields/combofield.cpp +++ b/project/effectfields/combofield.cpp @@ -25,6 +25,7 @@ QWidget *ComboField::CreateWidget() } connect(cb, SIGNAL(activated(int)), this, SLOT(UpdateFromWidget(int))); + connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); return cb; } diff --git a/project/effectfields/doublefield.cpp b/project/effectfields/doublefield.cpp index a0e9260e1..63de39fbb 100644 --- a/project/effectfields/doublefield.cpp +++ b/project/effectfields/doublefield.cpp @@ -71,6 +71,8 @@ QWidget *DoubleField::CreateWidget() ls->set_display_type(display_type_); ls->set_frame_rate(frame_rate_); + ls->setEnabled(IsEnabled()); + connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double))); connect(ls, SIGNAL(clicked()), this, SIGNAL(Clicked())); connect(this, SIGNAL(EnabledChanged(bool)), ls, SLOT(setEnabled(bool))); diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h index 166c801e0..b3fb60a29 100644 --- a/project/effectfields/effectfield.h +++ b/project/effectfields/effectfield.h @@ -85,6 +85,7 @@ private: signals: void Changed(); void Clicked(); + void EnabledChanged(bool); }; diff --git a/project/effectfields/filefield.cpp b/project/effectfields/filefield.cpp index 7ba52482e..a76383e15 100644 --- a/project/effectfields/filefield.cpp +++ b/project/effectfields/filefield.cpp @@ -1,5 +1,7 @@ #include "filefield.h" +#include "ui/embeddedfilechooser.h" + FileField::FileField(EffectRow* parent, const QString &id) : EffectField(parent, id, EFFECT_FIELD_FILE) { @@ -10,3 +12,18 @@ QString FileField::GetFileAt(double timecode) { return GetValueAt(timecode).toString(); } + +QWidget *FileField::CreateWidget() +{ + EmbeddedFileChooser* efc = new EmbeddedFileChooser(); + + connect(efc, SIGNAL(changed(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); + connect(this, SIGNAL(EnabledChanged(bool)), efc, SLOT(setEnabled(bool))); + + return efc; +} + +void FileField::UpdateFromWidget(const QString &s) +{ + SetValueAt(Now(), s); +} diff --git a/project/effectfields/filefield.h b/project/effectfields/filefield.h index 575a43c21..2a68a0b50 100644 --- a/project/effectfields/filefield.h +++ b/project/effectfields/filefield.h @@ -10,6 +10,10 @@ public: FileField(EffectRow* parent, const QString& id); QString GetFileAt(double timecode); + + virtual QWidget* CreateWidget() override; +private slots: + void UpdateFromWidget(const QString &s); }; #endif // FILEFIELD_H diff --git a/project/effectfields/fontfield.cpp b/project/effectfields/fontfield.cpp index 7c16f2eea..a7b14fc0c 100644 --- a/project/effectfields/fontfield.cpp +++ b/project/effectfields/fontfield.cpp @@ -1,12 +1,34 @@ #include "fontfield.h" +#include +#include + FontField::FontField(EffectRow* parent, const QString &id) : EffectField(parent, id, EFFECT_FIELD_FONT) { + font_list = QFontDatabase().families(); + SetValueAt(0, font_list.first()); } QString FontField::GetFontAt(double timecode) { return GetValueAt(timecode).toString(); } + +QWidget *FontField::CreateWidget() +{ + QComboBox* fcb = new QComboBox(); + + fcb->addItems(font_list); + + connect(fcb, SIGNAL(currentTextChanged(const QString &)), this, SLOT(UpdateFromWidget(const QString &))); + connect(this, SIGNAL(EnabledChanged(bool)), fcb, SLOT(setEnabled(bool))); + + return fcb; +} + +void FontField::UpdateFromWidget(const QString& s) +{ + SetValueAt(Now(), s); +} diff --git a/project/effectfields/fontfield.h b/project/effectfields/fontfield.h index 532f82d4d..b2a828b1d 100644 --- a/project/effectfields/fontfield.h +++ b/project/effectfields/fontfield.h @@ -9,6 +9,12 @@ public: FontField(EffectRow* parent, const QString& id); QString GetFontAt(double timecode); + + virtual QWidget *CreateWidget() override; +private: + QStringList font_list; +private slots: + void UpdateFromWidget(const QString& index); }; #endif // FONTFIELD_H diff --git a/project/effectfields/labelfield.cpp b/project/effectfields/labelfield.cpp index bf6db9238..e50f337d8 100644 --- a/project/effectfields/labelfield.cpp +++ b/project/effectfields/labelfield.cpp @@ -1,7 +1,18 @@ #include "labelfield.h" +#include + LabelField::LabelField(EffectRow *parent, const QString &string) : - EffectField(parent, nullptr, EFFECT_FIELD_UI) + EffectField(parent, nullptr, EFFECT_FIELD_UI), + label_text_(string) +{} + +QWidget *LabelField::CreateWidget() { - SetValueAt(0, string); + QLabel* label = new QLabel(label_text_); + + label->setEnabled(IsEnabled()); + connect(this, SIGNAL(EnabledChanged(bool)), label, SLOT(setEnabled(bool))); + + return label; } diff --git a/project/effectfields/labelfield.h b/project/effectfields/labelfield.h index e7dd712f2..628a9181a 100644 --- a/project/effectfields/labelfield.h +++ b/project/effectfields/labelfield.h @@ -8,6 +8,10 @@ class LabelField : public EffectField Q_OBJECT public: LabelField(EffectRow* parent, const QString& string); + + virtual QWidget* CreateWidget() override; +private: + QString label_text_; }; #endif // LABELFIELD_H diff --git a/project/effectfields/stringfield.cpp b/project/effectfields/stringfield.cpp index 322f40f6f..105e5c28f 100644 --- a/project/effectfields/stringfield.cpp +++ b/project/effectfields/stringfield.cpp @@ -20,6 +20,7 @@ QWidget *StringField::CreateWidget() { TextEditEx* text_edit = new TextEditEx(); + text_edit->setEnabled(IsEnabled()); text_edit->setUndoRedoEnabled(true); // the "2" looks like a magic number, but it's just one pixel on the top and the bottom @@ -28,6 +29,7 @@ QWidget *StringField::CreateWidget() + text_edit->document()->documentMargin() + 2)); connect(text_edit, SIGNAL(textModified(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); + connect(this, SIGNAL(EnabledChanged(bool)), text_edit, SLOT(setEnabled(bool))); return text_edit; } diff --git a/project/undo.cpp b/project/undo.cpp index 7c2ca0374..fd022f15c 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -197,7 +197,6 @@ AddEffectCommand::AddEffectCommand(Clip* c, EffectPtr e, const EffectMeta *m, in ref = e; meta = m; pos = insert_pos; - done = false; } void AddEffectCommand::doUndo() { @@ -207,7 +206,6 @@ void AddEffectCommand::doUndo() { } else { clip->effects.removeAt(pos); } - done = false; } void AddEffectCommand::doRedo() { @@ -219,7 +217,6 @@ void AddEffectCommand::doRedo() { } else { clip->effects.insert(pos, ref); } - done = true; } AddTransitionCommand::AddTransitionCommand(Clip* iopen, diff --git a/ui/colorbutton.cpp b/ui/colorbutton.cpp index 4489b47db..a5e200fbc 100644 --- a/ui/colorbutton.cpp +++ b/ui/colorbutton.cpp @@ -25,47 +25,47 @@ #include ColorButton::ColorButton(QWidget *parent) - : QPushButton(parent), color(Qt::white) { - set_button_color(); - connect(this, SIGNAL(clicked(bool)), this, SLOT(open_dialog())); + : QPushButton(parent), color(Qt::white) { + set_button_color(); + connect(this, SIGNAL(clicked(bool)), this, SLOT(open_dialog())); } QColor ColorButton::get_color() { - return color; + return color; } void ColorButton::set_color(QColor c) { - previousColor = color; - color = c; - set_button_color(); + previousColor = color; + color = c; + set_button_color(); } const QColor &ColorButton::getPreviousValue() { - return previousColor; + return previousColor; } void ColorButton::set_button_color() { - QPalette pal = palette(); - pal.setColor(QPalette::Button, color); - setPalette(pal); + QPalette pal = palette(); + pal.setColor(QPalette::Button, color); + setPalette(pal); } void ColorButton::open_dialog() { - QColor new_color = QColorDialog::getColor(color, nullptr, tr("Set Color")); - if (new_color.isValid() && color != new_color) { - set_color(new_color); - set_button_color(); - emit color_changed(); - } + QColor new_color = QColorDialog::getColor(color, nullptr, tr("Set Color")); + if (new_color.isValid() && color != new_color) { + set_color(new_color); + set_button_color(); + emit color_changed(color); + } } ColorCommand::ColorCommand(ColorButton* s, QColor o, QColor n) - : sender(s), old_color(o), new_color(n) {} + : sender(s), old_color(o), new_color(n) {} void ColorCommand::undo() { - sender->set_color(old_color); + sender->set_color(old_color); } void ColorCommand::redo() { - sender->set_color(new_color); + sender->set_color(new_color); } diff --git a/ui/colorbutton.h b/ui/colorbutton.h index d4593549f..74364d951 100644 --- a/ui/colorbutton.h +++ b/ui/colorbutton.h @@ -26,31 +26,31 @@ #include class ColorButton : public QPushButton { - Q_OBJECT + Q_OBJECT public: - ColorButton(QWidget* parent = 0); - QColor get_color(); - void set_color(QColor c); - const QColor& getPreviousValue(); + ColorButton(QWidget* parent = nullptr); + QColor get_color(); + void set_color(QColor c); + const QColor& getPreviousValue(); private: - QColor color; - QColor previousColor; - void set_button_color(); + QColor color; + QColor previousColor; + void set_button_color(); signals: - void color_changed(); + void color_changed(const QColor& c); private slots: - void open_dialog(); + void open_dialog(); }; class ColorCommand : public QUndoCommand { public: - ColorCommand(ColorButton* s, QColor o, QColor n); - void undo(); - void redo(); + ColorCommand(ColorButton* s, QColor o, QColor n); + void undo(); + void redo(); private: - ColorButton* sender; - QColor old_color; - QColor new_color; + ColorButton* sender; + QColor old_color; + QColor new_color; }; #endif // COLORBUTTON_H diff --git a/ui/comboboxex.h b/ui/comboboxex.h index 28c04d380..5a3d23772 100644 --- a/ui/comboboxex.h +++ b/ui/comboboxex.h @@ -25,18 +25,18 @@ #include class ComboBoxEx : public QComboBox { - Q_OBJECT + Q_OBJECT public: - ComboBoxEx(QWidget* parent = 0); - void setCurrentIndexEx(int i); - void setCurrentTextEx(const QString &text); - int getPreviousIndex(); + ComboBoxEx(QWidget* parent = 0); + void setCurrentIndexEx(int i); + void setCurrentTextEx(const QString &text); + int getPreviousIndex(); private slots: - void index_changed(int); + void index_changed(int); private: - int index; - int previousIndex; - void wheelEvent(QWheelEvent* e); + int index; + int previousIndex; + void wheelEvent(QWheelEvent* e); }; #endif // COMBOBOXEX_H diff --git a/ui/embeddedfilechooser.cpp b/ui/embeddedfilechooser.cpp index c5ca542d1..99e35905d 100644 --- a/ui/embeddedfilechooser.cpp +++ b/ui/embeddedfilechooser.cpp @@ -27,54 +27,54 @@ #include EmbeddedFileChooser::EmbeddedFileChooser(QWidget* parent) : QWidget(parent) { - QHBoxLayout* layout = new QHBoxLayout(this); - layout->setMargin(0); - file_label = new QLabel(this); - update_label(); - layout->addWidget(file_label); - QPushButton* browse_button = new QPushButton("...", this); - browse_button->setFixedWidth(25); - layout->addWidget(browse_button); - connect(browse_button, SIGNAL(clicked(bool)), this, SLOT(browse())); + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setMargin(0); + file_label = new QLabel(this); + update_label(); + layout->addWidget(file_label); + QPushButton* browse_button = new QPushButton("...", this); + browse_button->setFixedWidth(25); + layout->addWidget(browse_button); + connect(browse_button, SIGNAL(clicked(bool)), this, SLOT(browse())); } const QString &EmbeddedFileChooser::getFilename() { - return filename; + return filename; } const QString &EmbeddedFileChooser::getPreviousValue() { - return old_filename; + return old_filename; } void EmbeddedFileChooser::setFilename(const QString &s) { - old_filename = filename; - filename = s; - update_label(); - emit changed(); + old_filename = filename; + filename = s; + update_label(); + emit changed(filename); } void EmbeddedFileChooser::update_label() { - QString l = "" + tr("File:") + " "; - if (filename.isEmpty()) { - l += "(none)"; - } else { - bool file_exists = QFileInfo::exists(filename); - if (!file_exists) l += ""; - QString short_fn = filename.mid(filename.lastIndexOf('/')+1); - if (short_fn.size() > 20) { - l += "..." + short_fn.right(20); - } else { - l += short_fn; - } - if (!file_exists) l += ""; - } - l += ""; - file_label->setText(l); + QString l = "" + tr("File:") + " "; + if (filename.isEmpty()) { + l += "(none)"; + } else { + bool file_exists = QFileInfo::exists(filename); + if (!file_exists) l += ""; + QString short_fn = filename.mid(filename.lastIndexOf('/')+1); + if (short_fn.size() > 20) { + l += "..." + short_fn.right(20); + } else { + l += short_fn; + } + if (!file_exists) l += ""; + } + l += ""; + file_label->setText(l); } void EmbeddedFileChooser::browse() { - QString fn = QFileDialog::getOpenFileName(this); - if (!fn.isEmpty()) { - setFilename(fn); - } + QString fn = QFileDialog::getOpenFileName(this); + if (!fn.isEmpty()) { + setFilename(fn); + } } diff --git a/ui/embeddedfilechooser.h b/ui/embeddedfilechooser.h index 3808bec6f..9d15d1264 100644 --- a/ui/embeddedfilechooser.h +++ b/ui/embeddedfilechooser.h @@ -26,22 +26,22 @@ class QLabel; class EmbeddedFileChooser : public QWidget { - Q_OBJECT + Q_OBJECT public: - EmbeddedFileChooser(QWidget* parent = 0); + EmbeddedFileChooser(QWidget* parent = 0); - const QString& getFilename(); - const QString& getPreviousValue(); - void setFilename(const QString& s); + const QString& getFilename(); + const QString& getPreviousValue(); + void setFilename(const QString& s); signals: - void changed(); + void changed(const QString& s); private: - QLabel* file_label; - QString filename; - QString old_filename; - void update_label(); + QLabel* file_label; + QString filename; + QString old_filename; + void update_label(); private slots: - void browse(); + void browse(); }; #endif // EMBEDDEDFILECHOOSER_H diff --git a/ui/fontcombobox.cpp b/ui/fontcombobox.cpp index 349625847..4e5547c26 100644 --- a/ui/fontcombobox.cpp +++ b/ui/fontcombobox.cpp @@ -22,19 +22,19 @@ #include -FontCombobox::FontCombobox(QWidget* parent) : ComboBoxEx(parent) { - addItems(QFontDatabase().families()); +FontCombobox::FontCombobox(QWidget* parent) : QComboBox(parent) { + addItems(QFontDatabase().families()); - value = currentText(); + value = currentText(); - connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(updateInternals())); + connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(updateInternals())); } const QString& FontCombobox::getPreviousValue() { - return previousValue; + return previousValue; } void FontCombobox::updateInternals() { - previousValue = value; - value = currentText(); + previousValue = value; + value = currentText(); } diff --git a/ui/fontcombobox.h b/ui/fontcombobox.h index f6ad2d5dd..90fb24813 100644 --- a/ui/fontcombobox.h +++ b/ui/fontcombobox.h @@ -21,18 +21,18 @@ #ifndef FONTCOMBOBOX_H #define FONTCOMBOBOX_H -#include "comboboxex.h" +#include -class FontCombobox : public ComboBoxEx { - Q_OBJECT +class FontCombobox : public QComboBox { + Q_OBJECT public: - FontCombobox(QWidget* parent = 0); - const QString &getPreviousValue(); + FontCombobox(QWidget* parent = 0); + const QString &getPreviousValue(); private slots: - void updateInternals(); + void updateInternals(); private: - QString previousValue; - QString value; + QString previousValue; + QString value; }; #endif // FONTCOMBOBOX_H From 0176ae99becf7b28df57fe07c095e43c06203aa9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 08:54:58 +1100 Subject: [PATCH 14/56] restored minimum width functionality in effect controls --- panels/effectcontrols.cpp | 5 +++++ panels/effectcontrols.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index d82822d67..4feaa3e05 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -651,6 +651,11 @@ EffectsArea::EffectsArea(QWidget* parent) : QWidget(parent) {} +void EffectsArea::resizeEvent(QResizeEvent *) +{ + parent_widget->setMinimumWidth(sizeHint().width()); +} + void EffectsArea::receive_wheel_event(QWheelEvent *e) { QApplication::sendEvent(this, e); } diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h index 39482789b..767e57d3f 100644 --- a/panels/effectcontrols.h +++ b/panels/effectcontrols.h @@ -46,6 +46,8 @@ public: QScrollArea* parent_widget; KeyframeView* keyframe_area; TimelineHeader* header; +protected: + void resizeEvent(QResizeEvent*); public slots: void receive_wheel_event(QWheelEvent* e); }; From 686addf144f50d5b97df35e8a7e560f45fbc389b Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 08:55:15 +1100 Subject: [PATCH 15/56] reimplemented keyframe navigation --- ui/effectui.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 45d45a50c..c88e580dc 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -5,6 +5,7 @@ #include "project/clip.h" #include "ui/menuhelper.h" +#include "ui/keyframenavigator.h" EffectUI::EffectUI(Effect* e) : effect_(e) @@ -24,6 +25,8 @@ EffectUI::EffectUI(Effect* e) : this, SIGNAL(TitleBarContextMenuRequested(const QPoint&))); + int maximum_column = 0; + for (int i=0;irow_count();i++) { EffectRow* row = e->row(i); @@ -40,6 +43,26 @@ EffectUI::EffectUI(Effect* e) : layout_->addWidget(widget, i, j + 1); } + + // Find maximum column to place keyframe controls + maximum_column = qMax(row->FieldCount(), maximum_column); + } + + // Create keyframe controls + maximum_column++; + + for (int i=0;irow_count();i++) { + EffectRow* row = e->row(i); + + KeyframeNavigator* nav = new KeyframeNavigator(); + + connect(nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); + connect(nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); + connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); + connect(nav, SIGNAL(keyframe_enabled_changed(bool)), row, SLOT(SetKeyframingEnabled(bool))); + connect(nav, SIGNAL(clicked()), row, SLOT(FocusRow())); + + layout_->addWidget(nav, i, maximum_column); } connect(enabled_check, SIGNAL(clicked(bool)), e, SLOT(FieldChanged())); From 935cf04d952b71c655f9111f205b3a879b67e050 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 09:34:07 +1100 Subject: [PATCH 16/56] moved media to smart pointers --- io/loadthread.cpp | 19 ++-- io/loadthread.h | 2 +- panels/project.cpp | 52 +++++----- panels/project.h | 10 +- panels/timeline.cpp | 4 +- project/media.cpp | 26 +++-- project/media.h | 12 ++- project/projectmodel.cpp | 211 ++++++++++++++++++++------------------ project/projectmodel.h | 8 +- project/sourcescommon.cpp | 13 ++- project/undo.cpp | 71 +++---------- project/undo.h | 30 ++---- 12 files changed, 214 insertions(+), 244 deletions(-) diff --git a/io/loadthread.cpp b/io/loadthread.cpp index b8dbf9534..0e3582830 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -263,7 +263,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { switch (type) { case MEDIA_TYPE_FOLDER: { - Media* folder = panel_project->create_folder_internal(nullptr); + MediaPtr folder = panel_project->create_folder_internal(nullptr); folder->temp_id2 = 0; for (int j=0;j(); FootagePtr f(new Footage()); f->using_inout = false; @@ -381,7 +381,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { olive::project_model.appendChild(find_loaded_folder_by_id(folder), item); // analyze media to see if it's the same - loaded_media_items.append(item); + loaded_media_items.append(item.get()); } break; case MEDIA_TYPE_SEQUENCE: @@ -581,9 +581,9 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { } } - Media* m = panel_project->create_sequence_internal(nullptr, s, false, parent); + MediaPtr m = panel_project->create_sequence_internal(nullptr, s, false, parent); - loaded_sequences.append(m); + loaded_sequences.append(m.get()); } break; } @@ -600,7 +600,7 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { Media* LoadThread::find_loaded_folder_by_id(int id) { if (id == 0) return nullptr; for (int j=0;jtemp_id == id) { return parent_item; } @@ -632,12 +632,7 @@ void LoadThread::run() { error_str.clear(); show_err = true; - // temp variables for loading (unnecessary?) open_seq = nullptr; - loaded_folders.clear(); - loaded_media_items.clear(); - loaded_clips.clear(); - loaded_sequences.clear(); // get "element" count current_element_count = 0; @@ -669,7 +664,7 @@ void LoadThread::run() { if (cont) { // since folders loaded correctly, organize them appropriately for (int i=0;itemp_id2; olive::project_model.appendChild(find_loaded_folder_by_id(parent), folder); } diff --git a/io/loadthread.h b/io/loadthread.h index 22da99ded..5888bb99f 100644 --- a/io/loadthread.h +++ b/io/loadthread.h @@ -70,7 +70,7 @@ private: bool is_element(QXmlStreamReader& stream); - QVector loaded_folders; + QVector loaded_folders; QVector loaded_clips; QVector loaded_sequences; Media* find_loaded_folder_by_id(int id); diff --git a/panels/project.cpp b/panels/project.cpp index 0966c4ce7..86fe5dbf6 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -333,14 +333,14 @@ void Project::duplicate_selected() { void Project::replace_selected_file() { QModelIndexList selected_items = get_current_selected(); if (selected_items.size() == 1) { - Media* item = item_to_media(selected_items.at(0)); + MediaPtr item = item_to_media_ptr(selected_items.at(0)); if (item->get_type() == MEDIA_TYPE_FOOTAGE) { replace_media(item, nullptr); } } } -void Project::replace_media(Media* item, QString filename) { +void Project::replace_media(MediaPtr item, QString filename) { if (filename.isEmpty()) { filename = QFileDialog::getOpenFileName( this, @@ -412,10 +412,10 @@ void Project::open_properties() { } void Project::new_folder() { - Media* m = create_folder_internal(nullptr); + MediaPtr m = create_folder_internal(nullptr); olive::UndoStack.push(new AddMediaCommand(m, get_selected_folder())); - QModelIndex index = olive::project_model.create_index(m->row(), 0, m); + QModelIndex index = olive::project_model.create_index(m->row(), 0, m.get()); switch (olive::CurrentConfig.project_view_type) { case olive::PROJECT_VIEW_TREE: tree_view->edit(sorter->mapFromSource(index)); @@ -432,16 +432,16 @@ void Project::new_sequence() { nsd.exec(); } -Media* Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool open, Media* parent) { +MediaPtr Project::create_sequence_internal(ComboAction *ca, SequencePtr s, bool open, Media* parent) { if (parent == nullptr) { parent = olive::project_model.get_root(); } - Media* item = new Media(parent); + MediaPtr item = std::make_shared(parent); item->set_sequence(s); if (ca != nullptr) { - ca->append(new NewSequenceCommand(item, parent)); + ca->append(new AddMediaCommand(item, parent)); if (open) { ca->append(new ChangeSequenceAction(s)); @@ -460,26 +460,25 @@ QString Project::get_file_name_from_path(const QString& path) { return path.mid(path.lastIndexOf('/')+1); } -/*Media* Project::new_item() { - Media* item = new Media(0); - //item->setFlags(item->flags() | Qt::ItemIsEditable); - return item; -}*/ - bool Project::is_focused() { return tree_view->hasFocus() || icon_view->hasFocus(); } -Media* Project::create_folder_internal(QString name) { - Media* item = new Media(nullptr); +MediaPtr Project::create_folder_internal(QString name) { + MediaPtr item = std::make_shared(); item->set_folder(); item->set_name(name); return item; } -Media *Project::item_to_media(const QModelIndex &index) { +Media* Project::item_to_media(const QModelIndex &index) { return static_cast(sorter->mapToSource(index).internalPointer()); - // return static_cast(index.internalPointer()); +} + +MediaPtr Project::item_to_media_ptr(const QModelIndex &index) { + Media* raw_ptr = item_to_media(index); + + return raw_ptr->parentItem()->get_shared_ptr(raw_ptr); } void Project::get_all_media_from_table(QList& items, QList& list, int search_type) { @@ -514,10 +513,12 @@ bool delete_clips_in_clipboard_with_media(ComboAction* ca, Media* m) { void Project::delete_selected_media() { ComboAction* ca = new ComboAction(); QModelIndexList selected_items = get_current_selected(); + QList items; for (int i=0;i 0) { + QList media_items; get_all_media_from_table(items, media_items, MEDIA_TYPE_FOOTAGE); + for (int i=0;ito_footage(); @@ -618,7 +621,8 @@ void Project::delete_selected_media() { } for (int i=0;iappend(new DeleteMediaCommand(items.at(i))); + + ca->append(new DeleteMediaCommand(items.at(i)->parentItem()->get_shared_ptr(items.at(i)))); if (items.at(i)->get_type() == MEDIA_TYPE_SEQUENCE) { redraw = true; @@ -655,7 +659,7 @@ void Project::delete_selected_media() { } } -void Project::process_file_list(QStringList& files, bool recursive, Media* replace, Media* parent) { +void Project::process_file_list(QStringList& files, bool recursive, MediaPtr replace, Media* parent) { bool imported = false; // retrieve the array of image formats from the user's configuration @@ -678,7 +682,7 @@ void Project::process_file_list(QStringList& files, bool recursive, Media* repla if (QFileInfo(files.at(i)).isDir()) { QString folder_name = get_file_name_from_path(files.at(i)); - Media* folder = create_folder_internal(folder_name); + MediaPtr folder = create_folder_internal(folder_name); QDir directory(files.at(i)); directory.setFilter(QDir::NoDotAndDotDot | QDir::AllEntries); @@ -690,7 +694,7 @@ void Project::process_file_list(QStringList& files, bool recursive, Media* repla subdir_filenames.append(subdir_files.at(j).filePath()); } - process_file_list(subdir_filenames, true, nullptr, folder); + process_file_list(subdir_filenames, true, nullptr, folder.get()); if (create_undo_action) { ca->append(new AddMediaCommand(folder, parent)); @@ -852,13 +856,13 @@ void Project::process_file_list(QStringList& files, bool recursive, Media* repla // If we're not skipping this file, let's import it if (!skip) { - Media* item; + MediaPtr item; FootagePtr m; if (replace != nullptr) { item = replace; } else { - item = new Media(parent); + item = std::make_shared(parent); } m = FootagePtr(new Footage()); @@ -870,7 +874,7 @@ void Project::process_file_list(QStringList& files, bool recursive, Media* repla item->set_footage(m); - last_imported_media.append(item); + last_imported_media.append(item.get()); if (replace == nullptr) { if (create_undo_action) { diff --git a/panels/project.h b/panels/project.h index 4b1414f76..6c12294e3 100644 --- a/panels/project.h +++ b/panels/project.h @@ -58,10 +58,10 @@ public: bool is_focused(); void clear(); - Media* create_sequence_internal(ComboAction *ca, SequencePtr s, bool open, Media* parent); + MediaPtr create_sequence_internal(ComboAction *ca, SequencePtr s, bool open, Media* parent); QString get_next_sequence_name(QString start = nullptr); - void process_file_list(QStringList& files, bool recursive = false, Media* replace = nullptr, Media *parent = nullptr); - void replace_media(Media* item, QString filename); + void process_file_list(QStringList& files, bool recursive = false, MediaPtr replace = nullptr, Media *parent = nullptr); + void replace_media(MediaPtr item, QString filename); Media* get_selected_folder(); bool reveal_media(Media *media, QModelIndex parent = QModelIndex()); void add_recent_project(QString url); @@ -70,8 +70,10 @@ public: void load_project(const QString &filename, bool autorecovery, bool clear); void save_project(bool autorecovery); - Media* create_folder_internal(QString name); + MediaPtr create_folder_internal(QString name); + Media* item_to_media(const QModelIndex& index); + MediaPtr item_to_media_ptr(const QModelIndex &index); void save_recent_projects(); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 4170246e8..48db4b0df 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -444,11 +444,11 @@ void Timeline::nest() { relink_clips_using_ids(selected_clips, s->clips); // add sequence to project - Media* m = panel_project->create_sequence_internal(ca, s, false, nullptr); + MediaPtr m = panel_project->create_sequence_internal(ca, s, false, nullptr); // add nested sequence to active sequence QVector media_list; - media_list.append(m); + media_list.append(m.get()); create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list); add_clips_from_ghosts(ca, olive::ActiveSequence.get()); diff --git a/project/media.cpp b/project/media.cpp index b9d4508a2..bc0afa64b 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -67,12 +67,6 @@ Media::Media(Media* iparent) { type = -1; } -Media::~Media() { - for (int i=0;i(object.get()); } @@ -262,7 +256,7 @@ int Media::get_sampling_rate(int stream) { return 0; } -void Media::appendChild(Media *child) { +void Media::appendChild(MediaPtr child) { child->set_parent(this); children.append(child); } @@ -279,7 +273,7 @@ bool Media::setData(int col, const QVariant &value) { } Media *Media::child(int row) { - return children.value(row); + return children.value(row).get(); } int Media::childCount() const { @@ -348,7 +342,11 @@ QVariant Media::data(int column, int role) { int Media::row() const { if (parent) { - return parent->children.indexOf(const_cast(this)); + for (int i=0;ichildren.size();i++) { + if (parent->children.at(i).get() == this) { + return i; + } + } } return 0; } @@ -361,6 +359,16 @@ void Media::removeChild(int i) { children.removeAt(i); } +MediaPtr Media::get_shared_ptr(Media *m) +{ + for (int i=0;i &Media::get_markers() { // returns the marker array from the internal object // diff --git a/project/media.h b/project/media.h index b4f6c628d..3dd26f044 100644 --- a/project/media.h +++ b/project/media.h @@ -39,11 +39,14 @@ using SequencePtr = std::shared_ptr; using VoidPtr = std::shared_ptr; +class Media; +using MediaPtr = std::shared_ptr; + class Media { public: - Media(Media* iparent); - ~Media(); + Media(Media* iparent = nullptr); + Footage *to_footage(); SequencePtr to_sequence(); void set_icon(const QString& str); @@ -62,7 +65,7 @@ public: int get_sampling_rate(int stream = -1); // item functions - void appendChild(Media *child); + void appendChild(MediaPtr child); bool setData(int col, const QVariant &value); Media *child(int row); int childCount() const; @@ -71,6 +74,7 @@ public: int row() const; Media *parentItem(); void removeChild(int i); + MediaPtr get_shared_ptr(Media* m); // get markers from internal object QVector& get_markers(); @@ -84,7 +88,7 @@ private: VoidPtr object; // item functions - QList children; + QList children; Media* parent; QString folder_name; QString tooltip; diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index 268d7f01e..b1b5022c4 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -28,77 +28,77 @@ ProjectModel olive::project_model; -ProjectModel::ProjectModel(QObject *parent) : QAbstractItemModel(parent), root_item(nullptr) { - make_root(); +ProjectModel::ProjectModel(QObject *parent) : QAbstractItemModel(parent), root_item_(nullptr) { + make_root(); } ProjectModel::~ProjectModel() { - destroy_root(); + destroy_root(); } void ProjectModel::make_root() { - root_item = new Media(nullptr); - root_item->temp_id = 0; - root_item->root = true; + root_item_ = std::make_shared(); + root_item_->temp_id = 0; + root_item_->root = true; } void ProjectModel::destroy_root() { - if (panel_sequence_viewer != nullptr) panel_sequence_viewer->viewer_widget->delete_function(); - if (panel_footage_viewer != nullptr) panel_footage_viewer->viewer_widget->delete_function(); + if (panel_sequence_viewer != nullptr) panel_sequence_viewer->viewer_widget->delete_function(); + if (panel_footage_viewer != nullptr) panel_footage_viewer->viewer_widget->delete_function(); - if (root_item != nullptr) { - delete root_item; - } + root_item_ = std::make_shared(); } void ProjectModel::clear() { - beginResetModel(); - destroy_root(); - make_root(); - endResetModel(); + beginResetModel(); + destroy_root(); + make_root(); + endResetModel(); } -Media *ProjectModel::get_root() { - return root_item; +Media *ProjectModel::get_root() const { + return root_item_.get(); } QVariant ProjectModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) - return QVariant(); + if (!index.isValid()) + return QVariant(); - return static_cast(index.internalPointer())->data(index.column(), role); + return static_cast(index.internalPointer())->data(index.column(), role); } Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const { - if (!index.isValid()) - return Qt::ItemIsDropEnabled; + if (!index.isValid()) + return Qt::ItemIsDropEnabled; - return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable; + return QAbstractItemModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable; } QVariant ProjectModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return root_item->data(section, role); + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return root_item_->data(section, role); - return QVariant(); + return QVariant(); } QModelIndex ProjectModel::index(int row, int column, const QModelIndex &parent) const { - if (!hasIndex(row, column, parent)) - return QModelIndex(); + if (!hasIndex(row, column, parent)) + return QModelIndex(); - Media *parentItem; + Media *parentItem; - if (!parent.isValid()) - parentItem = root_item; - else - parentItem = static_cast(parent.internalPointer()); + if (!parent.isValid()) { + parentItem = get_root(); + } else { + parentItem = static_cast(parent.internalPointer()); + } - Media *childItem = parentItem->child(row); - if (childItem) - return createIndex(row, column, childItem); - else - return QModelIndex(); + Media *childItem = parentItem->child(row); + if (childItem) { + return createIndex(row, column, childItem); + } else { + return QModelIndex(); + } } QModelIndex ProjectModel::create_index(int arow, int acolumn, void* adata) { @@ -106,14 +106,14 @@ QModelIndex ProjectModel::create_index(int arow, int acolumn, void* adata) { } QModelIndex ProjectModel::parent(const QModelIndex &index) const { - if (!index.isValid()) - return QModelIndex(); + if (!index.isValid()) + return QModelIndex(); - Media *childItem = static_cast(index.internalPointer()); - Media *parentItem = childItem->parentItem(); + Media *childItem = static_cast(index.internalPointer()); + Media *parentItem = childItem->parentItem(); - if (parentItem == root_item) - return QModelIndex(); + if (parentItem == get_root()) + return QModelIndex(); return createIndex(parentItem->row(), 0, parentItem); } @@ -142,89 +142,104 @@ bool ProjectModel::hasChildren(const QModelIndex &parent) const } bool ProjectModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (role != Qt::EditRole) - return false; + if (role != Qt::EditRole) + return false; - Media *item = static_cast(index.internalPointer()); - bool result = item->setData(index.column(), value); + Media *item = static_cast(index.internalPointer()); + bool result = item->setData(index.column(), value); - if (result) - emit dataChanged(index, index); + if (result) + emit dataChanged(index, index); - return result; + return result; } int ProjectModel::rowCount(const QModelIndex &parent) const { Media *parentItem; - if (parent.column() > 0) - return 0; + if (parent.column() > 0) + return 0; - if (!parent.isValid()) { - parentItem = root_item; - } else { - parentItem = static_cast(parent.internalPointer()); - } + if (!parent.isValid()) { + parentItem = get_root(); + } else { + parentItem = static_cast(parent.internalPointer()); + } - return parentItem->childCount(); + return parentItem->childCount(); } int ProjectModel::columnCount(const QModelIndex &parent) const { - if (parent.isValid()) - return static_cast(parent.internalPointer())->columnCount(); - else - return root_item->columnCount(); + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return root_item_->columnCount(); } Media *ProjectModel::getItem(const QModelIndex &index) const { - if (index.isValid()) { - Media *item = static_cast(index.internalPointer()); - if (item) - return item; - } - return root_item; + if (index.isValid()) { + Media *item = static_cast(index.internalPointer()); + if (item) + return item; + } + return get_root(); } void ProjectModel::set_icon(Media* m, const QIcon &ico) { - QModelIndex index = createIndex(m->row(), 0, m); - m->set_icon(ico); - emit dataChanged(index, index); + QModelIndex index = createIndex(m->row(), 0, m); + m->set_icon(ico); + emit dataChanged(index, index); } -void ProjectModel::appendChild(Media *parent, Media *child) { - if (parent == nullptr) parent = root_item; - beginInsertRows(parent == root_item ? QModelIndex() : createIndex(parent->row(), 0, parent), parent->childCount(), parent->childCount()); - parent->appendChild(child); - endInsertRows(); +void ProjectModel::appendChild(Media* parent, MediaPtr child) { + if (parent == nullptr) { + parent = get_root(); + } + beginInsertRows(parent == get_root() ? + QModelIndex() : createIndex(parent->row(), 0, parent), parent->childCount(), parent->childCount()); + parent->appendChild(child); + endInsertRows(); } -void ProjectModel::moveChild(Media *child, Media *to) { - if (to == nullptr) to = root_item; - Media* from = child->parentItem(); - beginMoveRows( - from == root_item ? QModelIndex() : createIndex(from->row(), 0, from), - child->row(), - child->row(), - to == root_item ? QModelIndex() : createIndex(to->row(), 0, to), - to->childCount() - ); - from->removeChild(child->row()); - to->appendChild(child); - endMoveRows(); +void ProjectModel::moveChild(MediaPtr child, Media *to) { + if (to == nullptr) { + to = get_root(); + } + + Media* from = child->parentItem(); + + beginMoveRows( + from == get_root() ? QModelIndex() : createIndex(from->row(), 0, from), + child->row(), + child->row(), + to == get_root() ? QModelIndex() : createIndex(to->row(), 0, to), + to->childCount() + ); + + from->removeChild(child->row()); + to->appendChild(child); + endMoveRows(); } void ProjectModel::removeChild(Media* parent, Media* m) { - if (parent == nullptr) parent = root_item; - beginRemoveRows(parent == root_item ? QModelIndex() : createIndex(parent->row(), 0, parent), m->row(), m->row()); - parent->removeChild(m->row()); - endRemoveRows(); + if (parent == nullptr) { + parent = get_root(); + } + beginRemoveRows(parent == get_root() ? + QModelIndex() : createIndex(parent->row(), 0, parent), m->row(), m->row()); + parent->removeChild(m->row()); + endRemoveRows(); } Media* ProjectModel::child(int i, Media* parent) { - if (parent == nullptr) parent = root_item; - return parent->child(i); + if (parent == nullptr) { + parent = get_root(); + } + return parent->child(i); } int ProjectModel::childCount(Media *parent) { - if (parent == nullptr) parent = root_item; - return parent->childCount(); + if (parent == nullptr) { + parent = get_root(); + } + return parent->childCount(); } diff --git a/project/projectmodel.h b/project/projectmodel.h index b2ccc7c3a..17edade63 100644 --- a/project/projectmodel.h +++ b/project/projectmodel.h @@ -35,7 +35,7 @@ public: void make_root(); void destroy_root(); void clear(); - Media* get_root(); + Media* get_root() const; QVariant data(const QModelIndex &index, int role) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant headerData(int section, Qt::Orientation orientation, @@ -51,15 +51,15 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; Media* getItem(const QModelIndex &index) const; - void appendChild(Media* parent, Media* child); - void moveChild(Media* child, Media* to); + void appendChild(Media *parent, MediaPtr child); + void moveChild(MediaPtr child, Media* to); void removeChild(Media* parent, Media* m); Media* child(int i, Media* parent = nullptr); int childCount(Media* parent = nullptr); void set_icon(Media* m, const QIcon &ico); private: - Media* root_item; + MediaPtr root_item_; }; namespace olive { diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index c52f85f50..0156520e0 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -261,9 +261,12 @@ void SourcesCommon::mouseDoubleClickEvent(const QModelIndexList& selected_items) } } -void SourcesCommon::dropEvent(QWidget* parent, QDropEvent *event, const QModelIndex& drop_item, const QModelIndexList& items) { +void SourcesCommon::dropEvent(QWidget* parent, + QDropEvent *event, + const QModelIndex& drop_item, + const QModelIndexList& items) { const QMimeData* mimeData = event->mimeData(); - Media* m = project_parent->item_to_media(drop_item); + MediaPtr m = project_parent->item_to_media_ptr(drop_item); if (mimeData->hasUrls()) { // drag files in from outside QList urls = mimeData->urls(); @@ -305,11 +308,11 @@ void SourcesCommon::dropEvent(QWidget* parent, QDropEvent *event, const QModelIn // dragging files within project // if we dragged to the root OR dragged to a folder if (!drop_item.isValid() || m->get_type() == MEDIA_TYPE_FOLDER) { - QVector move_items; + QVector move_items; for (int i=0;iitem_to_media(item); + MediaPtr s = project_parent->item_to_media_ptr(item); if (parent != drop_item && item != drop_item) { bool ignore = false; if (parent.isValid()) { @@ -332,7 +335,7 @@ void SourcesCommon::dropEvent(QWidget* parent, QDropEvent *event, const QModelIn } if (move_items.size() > 0) { MediaMove* mm = new MediaMove(); - mm->to = m; + mm->to = m.get(); mm->items = move_items; olive::UndoStack.push(mm); } diff --git a/project/undo.cpp b/project/undo.cpp index fd022f15c..977494e79 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -322,76 +322,32 @@ void DeleteTransitionCommand::doRedo() { } } -NewSequenceCommand::NewSequenceCommand(Media *s, Media* iparent) { - seq = s; - parent = iparent; - done = false; - - if (parent == nullptr) parent = olive::project_model.get_root(); -} - -NewSequenceCommand::~NewSequenceCommand() { - if (!done) delete seq; -} - -void NewSequenceCommand::doUndo() { - olive::project_model.removeChild(parent, seq); - - done = false; -} - -void NewSequenceCommand::doRedo() { - olive::project_model.appendChild(parent, seq); - - done = true; -} - -AddMediaCommand::AddMediaCommand(Media* iitem, Media *iparent) { - item = iitem; - parent = iparent; - done = false; -} - -AddMediaCommand::~AddMediaCommand() { - if (!done) { - delete item; - } +AddMediaCommand::AddMediaCommand(MediaPtr iitem, Media *iparent) : + item(iitem), + parent(iparent) +{ } void AddMediaCommand::doUndo() { - olive::project_model.removeChild(parent, item); - done = false; - + olive::project_model.removeChild(parent, item.get()); } void AddMediaCommand::doRedo() { olive::project_model.appendChild(parent, item); - - done = true; } -DeleteMediaCommand::DeleteMediaCommand(Media* i) { - item = i; - parent = i->parentItem(); -} - -DeleteMediaCommand::~DeleteMediaCommand() { - if (done) { - delete item; - } +DeleteMediaCommand::DeleteMediaCommand(MediaPtr i) : + item(i), + parent(i->parentItem()) +{ } void DeleteMediaCommand::doUndo() { olive::project_model.appendChild(parent, item); - - - done = false; } void DeleteMediaCommand::doRedo() { - olive::project_model.removeChild(parent, item); - - done = true; + olive::project_model.removeChild(parent, item.get()); } AddClipCommand::AddClipCommand(Sequence *s, QVector& add) { @@ -501,7 +457,7 @@ void CheckboxCommand::doRedo() { } } -ReplaceMediaCommand::ReplaceMediaCommand(Media* i, QString s) { +ReplaceMediaCommand::ReplaceMediaCommand(MediaPtr i, QString s) { item = i; new_filename = s; old_filename = item->to_footage()->url; @@ -514,7 +470,7 @@ void ReplaceMediaCommand::replace(QString& filename) { Sequence* s = all_sequences.at(i)->to_sequence().get(); for (int j=0;jclips.size();j++) { ClipPtr c = s->clips.at(j); - if (c != nullptr && c->media() == item && c->IsOpen()) { + if (c != nullptr && c->media() == item.get() && c->IsOpen()) { c->Close(true); c->replaced = true; } @@ -525,7 +481,7 @@ void ReplaceMediaCommand::replace(QString& filename) { QStringList files; files.append(filename); panel_project->process_file_list(files, false, item, nullptr); - PreviewGenerator::AnalyzeMedia(item); + PreviewGenerator::AnalyzeMedia(item.get()); } void ReplaceMediaCommand::doUndo() { @@ -615,7 +571,6 @@ void MediaMove::doUndo() { for (int i=0;i items; + QVector items; Media* to; virtual void doUndo() override; virtual void doRedo() override; From 3213749adf263c829d41c23939d8e59425d910bc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 09:42:50 +1100 Subject: [PATCH 17/56] minor code improvements --- project/effectgizmo.cpp | 2 ++ project/undo.cpp | 29 ++++++++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/project/effectgizmo.cpp b/project/effectgizmo.cpp index f2c8eba08..9d3413708 100644 --- a/project/effectgizmo.cpp +++ b/project/effectgizmo.cpp @@ -37,6 +37,8 @@ EffectGizmo::EffectGizmo(Effect *parent, int type) : type(type), cursor(-1) { + Q_ASSERT(parent != nullptr); + int point_count = (type == GIZMO_TYPE_POLY) ? 4 : 1; world_pos.resize(point_count); screen_pos.resize(point_count); diff --git a/project/undo.cpp b/project/undo.cpp index 977494e79..34bf06794 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -992,11 +992,12 @@ void ReloadEffectsCommand::doRedo() { panel_effect_controls->Reload(); } -RippleAction::RippleAction(Sequence *is, long ipoint, long ilength, const QVector &iignore) { - s = is; - point = ipoint; - length = ilength; - ignore = iignore; +RippleAction::RippleAction(Sequence *is, long ipoint, long ilength, const QVector &iignore) : + s(is), + point(ipoint), + length(ilength), + ignore(iignore) +{ } void RippleAction::doUndo() { @@ -1019,10 +1020,11 @@ void RippleAction::doRedo() { ca->redo(); } -SetDouble::SetDouble(double* pointer, double old_value, double new_value) { - p = pointer; - oldval = old_value; - newval = new_value; +SetDouble::SetDouble(double* pointer, double old_value, double new_value) : + p(pointer), + oldval(old_value), + newval(new_value) +{ } void SetDouble::doUndo() { @@ -1034,10 +1036,11 @@ void SetDouble::doRedo() { *p = newval; } -SetQVariant::SetQVariant(QVariant *itarget, const QVariant &iold, const QVariant &inew) { - target = itarget; - old_val = iold; - new_val = inew; +SetQVariant::SetQVariant(QVariant *itarget, const QVariant &iold, const QVariant &inew) : + target(itarget), + old_val(iold), + new_val(inew) +{ } void SetQVariant::doUndo() { From 36f3d0ac9244ccc5f1e5415ddfe92f611e0e1107 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 09:44:39 +1100 Subject: [PATCH 18/56] only show update notif if compiled to --- ui/updatenotification.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/updatenotification.cpp b/ui/updatenotification.cpp index aca2f47b7..595a6b51f 100644 --- a/ui/updatenotification.cpp +++ b/ui/updatenotification.cpp @@ -14,7 +14,7 @@ UpdateNotification::UpdateNotification() void UpdateNotification::check() { -#if defined(GITHASH) && (defined(_WIN32) || defined(__APPLE__)) +#if defined(GITHASH) && defined(UPDATEMSG) QNetworkAccessManager* manager = new QNetworkAccessManager(); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(finished_slot(QNetworkReply *))); From ec5ee40deeb4e9f58e5c1a48b96da0bd2ad71da0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 10:22:30 +1100 Subject: [PATCH 19/56] respect field column span and disable scrolling on combo fields --- project/effectfields/combofield.cpp | 6 ++- project/effectfields/effectfield.cpp | 4 +- project/effectfields/fontfield.cpp | 7 ++- ui/comboboxex.cpp | 64 ++++++---------------------- ui/comboboxex.h | 15 +++---- ui/effectui.cpp | 5 ++- 6 files changed, 33 insertions(+), 68 deletions(-) diff --git a/project/effectfields/combofield.cpp b/project/effectfields/combofield.cpp index 46576aa7a..2058e9661 100644 --- a/project/effectfields/combofield.cpp +++ b/project/effectfields/combofield.cpp @@ -1,6 +1,6 @@ #include "combofield.h" -#include +#include "ui/comboboxex.h" ComboField::ComboField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_COMBO) @@ -18,7 +18,9 @@ void ComboField::AddItem(const QString &text, const QVariant &data) QWidget *ComboField::CreateWidget() { - QComboBox* cb = new QComboBox(); + ComboBoxEx* cb = new ComboBoxEx(); + + cb->setScrollingEnabled(false); for (int i=0;iaddItem(items_.at(i).name); diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp index b71154022..a3db48cea 100644 --- a/project/effectfields/effectfield.cpp +++ b/project/effectfields/effectfield.cpp @@ -50,7 +50,8 @@ EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) QObject(parent), type_(t), id_(i), - enabled_(true) + enabled_(true), + colspan_(1) { // EffectField MUST be created with a parent. Q_ASSERT(parent != nullptr); @@ -80,6 +81,7 @@ int EffectField::GetColumnSpan() void EffectField::SetColumnSpan(int i) { + Q_ASSERT(i >= 1); colspan_ = i; } diff --git a/project/effectfields/fontfield.cpp b/project/effectfields/fontfield.cpp index a7b14fc0c..b647dd17e 100644 --- a/project/effectfields/fontfield.cpp +++ b/project/effectfields/fontfield.cpp @@ -1,8 +1,9 @@ #include "fontfield.h" -#include #include +#include "ui/comboboxex.h" + FontField::FontField(EffectRow* parent, const QString &id) : EffectField(parent, id, EFFECT_FIELD_FONT) { @@ -18,7 +19,9 @@ QString FontField::GetFontAt(double timecode) QWidget *FontField::CreateWidget() { - QComboBox* fcb = new QComboBox(); + ComboBoxEx* fcb = new ComboBoxEx(); + + fcb->setScrollingEnabled(false); fcb->addItems(font_list); diff --git a/ui/comboboxex.cpp b/ui/comboboxex.cpp index 254504eab..3306ffbc1 100644 --- a/ui/comboboxex.cpp +++ b/ui/comboboxex.cpp @@ -20,63 +20,23 @@ #include "comboboxex.h" -#include "project/undo.h" -#include "panels/project.h" -#include "mainwindow.h" - -#include #include - -class ComboBoxExCommand : public QUndoCommand { -public: - ComboBoxExCommand(ComboBoxEx* obj, int old_index, int new_index) : - combobox(obj), old_val(old_index), new_val(new_index), done(true), old_project_changed(olive::MainWindow->isWindowModified()) {} - void undo() { - combobox->setCurrentIndex(old_val); - done = false; - olive::MainWindow->setWindowModified(old_project_changed); - } - void redo() { - if (!done) { - combobox->setCurrentIndex(new_val); - } - olive::MainWindow->setWindowModified(true); - } -private: - ComboBoxEx* combobox; - int old_val; - int new_val; - bool done; - bool old_project_changed; -}; - -ComboBoxEx::ComboBoxEx(QWidget *parent) : QComboBox(parent), index(0) { - connect(this, SIGNAL(activated(int)), this, SLOT(index_changed(int))); +ComboBoxEx::ComboBoxEx(QWidget *parent) : + QComboBox(parent) +{ } -void ComboBoxEx::setCurrentIndexEx(int i) { - index = i; - setCurrentIndex(i); +void ComboBoxEx::setScrollingEnabled(bool b) +{ + scrolling_enabled_ = b; } -void ComboBoxEx::setCurrentTextEx(const QString &text) { - setCurrentText(text); - index = currentIndex(); -} - -int ComboBoxEx::getPreviousIndex() { - return previousIndex; -} - -void ComboBoxEx::index_changed(int i) { - if (index != i) { - previousIndex = index; -// undo_stack.push(new ComboBoxExCommand(this, index, i)); - index = i; - } -} - -void ComboBoxEx::wheelEvent(QWheelEvent* e) { +void ComboBoxEx::wheelEvent(QWheelEvent *e) +{ + if (scrolling_enabled_) { + QComboBox::wheelEvent(e); + } else { e->ignore(); + } } diff --git a/ui/comboboxex.h b/ui/comboboxex.h index 5a3d23772..e3b7bb6b3 100644 --- a/ui/comboboxex.h +++ b/ui/comboboxex.h @@ -22,21 +22,16 @@ #define COMBOBOXEX_H #include -#include class ComboBoxEx : public QComboBox { Q_OBJECT public: - ComboBoxEx(QWidget* parent = 0); - void setCurrentIndexEx(int i); - void setCurrentTextEx(const QString &text); - int getPreviousIndex(); -private slots: - void index_changed(int); + ComboBoxEx(QWidget* parent = nullptr); + void setScrollingEnabled(bool b); +protected: + virtual void wheelEvent(QWheelEvent* e) override; private: - int index; - int previousIndex; - void wheelEvent(QWheelEvent* e); + bool scrolling_enabled_; }; #endif // COMBOBOXEX_H diff --git a/ui/effectui.cpp b/ui/effectui.cpp index c88e580dc..cc56e7aff 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -36,12 +36,15 @@ EffectUI::EffectUI(Effect* e) : layout_->addWidget(row_label, i, 0); + int column = 1; for (int j=0;jFieldCount();j++) { EffectField* field = row->Field(j); QWidget* widget = field->CreateWidget(); - layout_->addWidget(widget, i, j + 1); + layout_->addWidget(widget, i, column, 1, field->GetColumnSpan()); + + column += field->GetColumnSpan(); } // Find maximum column to place keyframe controls From d84b5a7f1dc65595fabe74490f356507e487f132 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 11:30:25 +1100 Subject: [PATCH 20/56] reimplemented some of keyframing --- project/effect.cpp | 9 +- project/effectfields/effectfield.cpp | 99 +++++++++++++++++-- project/effectfields/effectfield.h | 15 ++- project/effectrow.cpp | 143 +++++++++++++-------------- project/effectrow.h | 4 +- project/undo.cpp | 4 +- ui/keyframenavigator.cpp | 3 +- ui/keyframenavigator.h | 32 +++--- 8 files changed, 195 insertions(+), 114 deletions(-) diff --git a/project/effect.cpp b/project/effect.cpp index f32598be5..43d2e2ec2 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -351,7 +351,7 @@ void Effect::copy_field_keyframes(EffectPtr e) { for (int i=0;irows.at(i); - copy_row->SetKeyframing(row->IsKeyframing()); + copy_row->SetKeyframingInternal(row->IsKeyframing()); for (int j=0;jFieldCount();j++) { // Get field from this (the source) effect EffectField* field = row->Field(j); @@ -390,8 +390,7 @@ int Effect::gizmo_count() { void Effect::refresh() {} void Effect::FieldChanged() { - panel_sequence_viewer->viewer_widget->frame_update(); - panel_graph_editor->update_panel(); + update_ui(false); } void Effect::delete_self() { @@ -545,7 +544,7 @@ void Effect::load(QXmlStreamReader& stream) { // read keyframes if (stream.name() == "key" && stream.isStartElement()) { - row->SetKeyframing(true); + row->SetKeyframingInternal(true); EffectKeyframe key; for (int k=0;kSetKeyframing(false); + row->SetKeyframingInternal(false); for (int j=0;jFieldCount();j++) { EffectField* field = row->Field(j); field->keyframes.clear(); diff --git a/project/effectfields/effectfield.cpp b/project/effectfields/effectfield.cpp index a3db48cea..0fe9421a1 100644 --- a/project/effectfields/effectfield.cpp +++ b/project/effectfields/effectfield.cpp @@ -125,26 +125,58 @@ QVariant EffectField::GetValueAt(double timecode) double after_dbl = after_key.data.toDouble(); if (before_key.type == EFFECT_KEYFRAME_HOLD) { - // hold + + // Hold keyframes will always return the previous keyframe with no interpolation value = before_dbl; + } else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) { + // bezier interpolation if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { + // cubic bezier - double t = cubic_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), 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); + double t = cubic_t_from_x(timecodeToFrame(timecode), + before_key.time, + before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), + after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), + 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); + } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier + // last keyframe is the bezier one - double t = quad_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time); - value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t); + double t = quad_t_from_x(timecodeToFrame(timecode), + before_key.time, + before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), + after_key.time); + + value = quad_from_t(before_dbl, + before_dbl+before_key.post_handle_y, + after_dbl, + t); + } else { // this keyframe is the bezier one - double t = quad_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); - value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t); + double t = quad_t_from_x(timecodeToFrame(timecode), + before_key.time, + after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), + after_key.time); + + value = quad_from_t(before_dbl, + after_dbl+after_key.pre_handle_y, + after_dbl, + t); } } else { - // linear + + // Linear interpolation (default) value = double_lerp(before_dbl, after_dbl, progress); + } } return value; @@ -175,7 +207,7 @@ QVariant EffectField::GetValueAt(double timecode) return keyframes.first().data; } -void EffectField::SetValueAt(double timecode, const QVariant &value) +void EffectField::SetValueAt(double time, const QVariant &value) { if (keyframes.isEmpty()) { EffectKeyframe key; @@ -185,7 +217,32 @@ void EffectField::SetValueAt(double timecode, const QVariant &value) } if (GetParentRow()->IsKeyframing()) { - // create keyframe here + + // Create keyframe here + + // Convert seconds timecode to frame + long frame_timecode = timecodeToFrame(time); + + // Check array if a keyframe at this time already exists + int keyframe_index = -1; + for (int i=0;isequence->playhead); } +void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) +{ + if (enabled) { + + // Convert "perpetual" keyframe to a keyframe at this time + ca->append(new SetLong(&keyframes.first().time, keyframes.first().time, timecodeToFrame(Now()))); + + } else { + + // Convert keyframes to one "perpetual" keyframe + + // Set first keyframe to whatever the data is now + ca->append(new SetQVariant(&keyframes.first().data, keyframes.first().data, GetValueAt(Now()))); + + // Delete all keyframes except the first + for (int i=1;iappend(new KeyframeDelete(this, 1)); + } + + } +} + const EffectField::EffectFieldType &EffectField::type() { return type_; diff --git a/project/effectfields/effectfield.h b/project/effectfields/effectfield.h index b3fb60a29..08fce79bb 100644 --- a/project/effectfields/effectfield.h +++ b/project/effectfields/effectfield.h @@ -53,10 +53,12 @@ public: const QString& id(); QVariant GetValueAt(double timecode); - void SetValueAt(double timecode, const QVariant& value); + void SetValueAt(double time, const QVariant& value); double Now(); + void PrepareDataForKeyframing(bool enabled, ComboAction* ca); + int GetColumnSpan(); void SetColumnSpan(int i); @@ -69,8 +71,15 @@ public: bool IsEnabled(); void SetEnabled(bool e); + QVector keyframes; +signals: + void Changed(); + void Clicked(); + + void EnabledChanged(bool); + private: EffectFieldType type_; QString id_; @@ -82,11 +91,7 @@ private: bool enabled_; int colspan_; -signals: - void Changed(); - void Clicked(); - void EnabledChanged(bool); }; #endif // EFFECTFIELD_H diff --git a/project/effectrow.cpp b/project/effectrow.cpp index 779f97051..a1337fb7b 100644 --- a/project/effectrow.cpp +++ b/project/effectrow.cpp @@ -58,7 +58,7 @@ bool EffectRow::IsKeyframing() { return keyframing_; } -void EffectRow::SetKeyframing(bool b) { +void EffectRow::SetKeyframingInternal(bool b) { if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) { keyframing_ = b; emit KeyframingSetChanged(keyframing_); @@ -72,28 +72,46 @@ bool EffectRow::IsSavable() void EffectRow::SetKeyframingEnabled(bool enabled) { if (enabled) { + ComboAction* ca = new ComboAction(); + + // Enable keyframing setting on this row ca->append(new SetIsKeyframing(this, true)); - set_keyframe_now(ca); + + // Prepare each field's data to start keyframing + for (int i=0;iPrepareDataForKeyframing(true, ca); + } + olive::UndoStack.push(ca); + } else { + + // Confirm with the user whether they really want to disable keyframing if (QMessageBox::question(panel_effect_controls, tr("Disable Keyframes"), - tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"), + tr("Disabling keyframes will delete all current keyframes. " + "Are you sure you want to do this?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - // clear + ComboAction* ca = new ComboAction(); + + // Prepare each field's data to stop keyframing for (int i=0;ikeyframes.size();j++) { - ca->append(new KeyframeDelete(f, 0)); - } + Field(i)->PrepareDataForKeyframing(false, ca); } + + // Disable keyframing setting on this row ca->append(new SetIsKeyframing(this, false)); + olive::UndoStack.push(ca); panel_effect_controls->update_keyframes(); + } else { - SetKeyframing(true); + + + SetKeyframingInternal(true); + } } } @@ -101,42 +119,73 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { void EffectRow::GoToPreviousKeyframe() { long key = LONG_MIN; Clip* c = GetParentEffect()->parent_clip; + long sequence_playhead = c->sequence->playhead; + + // Used to convert clip frame number to sequence frame number + long time_adjustment = c->timeline_in() - c->clip_in(); + + // Loop through all of this row's fields for (int i=0;ikeyframes.size();j++) { - long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in(); - if (comp < olive::ActiveSequence->playhead) { + long comp = f->keyframes.at(j).time + time_adjustment; + + // Get the closest keyframe + if (comp < sequence_playhead) { key = qMax(comp, key); } } } + + // If we found a keyframe less than the playhead, jump to it if (key != LONG_MIN) panel_sequence_viewer->seek(key); } void EffectRow::ToggleKeyframe() { + Clip* c = GetParentEffect()->parent_clip; + long sequence_playhead = c->sequence->playhead; + + // Used to convert clip frame number to sequence frame number + long time_adjustment = c->timeline_in() - c->clip_in(); + QVector key_fields; QVector key_field_index; - Clip* c = GetParentEffect()->parent_clip; + + // See if any keyframes on any fields are at the current time for (int j=0;jkeyframes.size();i++) { - long comp = c->timeline_in() - c->clip_in() + f->keyframes.at(i).time; - if (comp == olive::ActiveSequence->playhead) { + long comp = f->keyframes.at(i).time + time_adjustment; + + if (comp == sequence_playhead) { + + // Cache the keyframes if they are at the current time key_fields.append(f); key_field_index.append(i); + } } } ComboAction* ca = new ComboAction(); - if (key_fields.size() == 0) { - // keyframe doesn't exist, set one - set_keyframe_now(ca); + + if (key_fields.isEmpty()) { + + // If we didn't find any current keyframes, create one for each field + SetKeyframeOnAllFields(ca); + } else { + + // If we DID find keyframes at this time, delete them for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); } + } + olive::UndoStack.push(ca); update_ui(false); } @@ -160,65 +209,13 @@ void EffectRow::FocusRow() { panel_graph_editor->set_row(this); } -void EffectRow::set_keyframe_now(ComboAction* ca) { - // TODO address this... - /* - long time = olive::ActiveSequence->playhead - - parent_effect->parent_clip->timeline_in() - + parent_effect->parent_clip->clip_in(); - - if (!just_made_unsafe_keyframe) { - EffectKeyframe key; - key.time = time; - - unsafe_keys.resize(fieldCount()); - unsafe_old_data.resize(fieldCount()); - key_is_new.resize(fieldCount()); - - for (int i=0;ikeyframes.size();j++) { - if (f->keyframes.at(j).time == time) { - exist_key = j; - } else if (f->keyframes.at(j).time < time - && f->keyframes.at(closest_key).time < f->keyframes.at(j).time) { - closest_key = j; - } - } - if (exist_key == -1) { - key.type = (f->keyframes.size() == 0) ? EFFECT_KEYFRAME_LINEAR : f->keyframes.at(closest_key).type; - key.data = f->GetCurrentValue(); - unsafe_keys[i] = f->keyframes.size(); - f->keyframes.append(key); - key_is_new[i] = true; - } else { - unsafe_keys[i] = exist_key; - key_is_new[i] = false; - } - unsafe_old_data[i] = f->GetCurrentValue(); - } - just_made_unsafe_keyframe = true; - } - - for (int i=0;ikeyframes[unsafe_keys.at(i)].data = field(i)->GetCurrentValue(); - } - - if (ca != nullptr) { - for (int i=0;iappend(new KeyframeFieldSet(field(i), unsafe_keys.at(i))); - ca->append(new SetQVariant(&field(i)->keyframes[unsafe_keys.at(i)].data, unsafe_old_data.at(i), field(i)->GetCurrentValue())); - } - unsafe_keys.clear(); - unsafe_old_data.clear(); - just_made_unsafe_keyframe = false; +void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) { + for (int i=0;iSetValueAt(field->Now(), field->GetValueAt(field->Now())); } panel_effect_controls->update_keyframes(); - */ } void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) { diff --git a/project/effectrow.h b/project/effectrow.h index a59486941..b3be99aed 100644 --- a/project/effectrow.h +++ b/project/effectrow.h @@ -45,7 +45,7 @@ public: EffectField* Field(int i); int FieldCount(); - void set_keyframe_now(ComboAction *ca); + void SetKeyframeOnAllFields(ComboAction *ca); void delete_keyframe_at_time(ComboAction *ca, long time); Effect* GetParentEffect(); @@ -53,7 +53,7 @@ public: const QString& name(); bool IsKeyframing(); - void SetKeyframing(bool); + void SetKeyframingInternal(bool); bool IsSavable(); public slots: diff --git a/project/undo.cpp b/project/undo.cpp index 34bf06794..1aa79eab3 100644 --- a/project/undo.cpp +++ b/project/undo.cpp @@ -1092,11 +1092,11 @@ SetIsKeyframing::SetIsKeyframing(EffectRow *irow, bool ib) { } void SetIsKeyframing::doUndo() { - row->SetKeyframing(!b); + row->SetKeyframingInternal(!b); } void SetIsKeyframing::doRedo() { - row->SetKeyframing(b); + row->SetKeyframingInternal(b); } RefreshClips::RefreshClips(Media *m) { diff --git a/ui/keyframenavigator.cpp b/ui/keyframenavigator.cpp index bf90d66e1..18625b26d 100644 --- a/ui/keyframenavigator.cpp +++ b/ui/keyframenavigator.cpp @@ -60,7 +60,8 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent, bool addLeftPad) : QWidget 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(olive::icon::Clock, "", this); + keyframe_enable = new QPushButton(this); + keyframe_enable->setIcon(olive::icon::Clock); keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); keyframe_enable->setIconSize(keyframe_enable->iconSize()*0.75); keyframe_enable->setCheckable(true); diff --git a/ui/keyframenavigator.h b/ui/keyframenavigator.h index c82b7344d..b0141aeb1 100644 --- a/ui/keyframenavigator.h +++ b/ui/keyframenavigator.h @@ -28,26 +28,26 @@ class QPushButton; class KeyframeNavigator : public QWidget { - Q_OBJECT + Q_OBJECT public: - KeyframeNavigator(QWidget* parent = 0, bool addLeftPad = true); - ~KeyframeNavigator(); - void enable_keyframes(bool); - void enable_keyframe_toggle(bool); + KeyframeNavigator(QWidget* parent = nullptr, bool addLeftPad = true); + ~KeyframeNavigator(); + void enable_keyframes(bool); + void enable_keyframe_toggle(bool); signals: - void goto_previous_key(); - void toggle_key(); - void goto_next_key(); - void keyframe_enabled_changed(bool); - void clicked(); + void goto_previous_key(); + void toggle_key(); + void goto_next_key(); + void keyframe_enabled_changed(bool); + void clicked(); private slots: - void keyframe_ui_enabled(bool); + void keyframe_ui_enabled(bool); private: - QHBoxLayout* key_controls; - QPushButton* left_key_nav; - QPushButton* key_addremove; - QPushButton* right_key_nav; - QPushButton* keyframe_enable; + QHBoxLayout* key_controls; + QPushButton* left_key_nav; + QPushButton* key_addremove; + QPushButton* right_key_nav; + QPushButton* keyframe_enable; }; #endif // KEYFRAMENAVIGATOR_H From 1cd5dabc075ce2c91f41ac12ec493724612fe785 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 16:55:49 +1100 Subject: [PATCH 21/56] file/folder restructuring --- dialogs/advancedvideodialog.h | 2 +- dialogs/clippropertiesdialog.cpp | 18 +- dialogs/clippropertiesdialog.h | 2 +- dialogs/exportdialog.cpp | 6 +- dialogs/exportdialog.h | 4 +- dialogs/loaddialog.cpp | 4 +- dialogs/loaddialog.h | 2 +- dialogs/mediapropertiesdialog.cpp | 2 +- dialogs/newsequencedialog.cpp | 6 +- dialogs/newsequencedialog.h | 2 +- dialogs/preferencesdialog.cpp | 8 +- dialogs/proxydialog.cpp | 4 +- dialogs/replaceclipmediadialog.cpp | 136 ++++----- dialogs/speeddialog.cpp | 48 ++-- dialogs/speeddialog.h | 2 +- dialogs/speeddialog.ui | 107 ------- effects/README | 1 - {project => effects}/effect.cpp | 18 +- {project => effects}/effect.h | 0 .../effectfields => effects}/effectfield.cpp | 95 +++--- .../effectfields => effects}/effectfield.h | 5 +- effects/effectfields.h | 14 + {project => effects}/effectgizmo.cpp | 0 {project => effects}/effectgizmo.h | 0 effects/effectloaders.cpp | 271 ++++++++++++++++++ {project => effects}/effectloaders.h | 0 {project => effects}/effectrow.cpp | 6 +- {project => effects}/effectrow.h | 0 .../fields}/boolfield.cpp | 14 + .../fields}/boolfield.h | 3 +- .../fields}/buttonfield.cpp | 0 .../fields}/buttonfield.h | 2 +- .../fields}/colorfield.cpp | 0 .../fields}/colorfield.h | 2 +- .../fields}/combofield.cpp | 0 .../fields}/combofield.h | 2 +- .../fields}/doublefield.cpp | 19 +- .../fields}/doublefield.h | 3 +- .../fields}/filefield.cpp | 0 .../fields}/filefield.h | 2 +- .../fields}/fontfield.cpp | 0 .../fields}/fontfield.h | 2 +- .../fields}/labelfield.cpp | 0 .../fields}/labelfield.h | 2 +- .../fields}/stringfield.cpp | 2 +- .../fields}/stringfield.h | 2 +- effects/internal/audionoiseeffect.h | 2 +- effects/internal/cornerpineffect.cpp | 6 +- effects/internal/cornerpineffect.h | 2 +- effects/internal/crossdissolvetransition.h | 2 +- effects/internal/cubetransition.h | 2 +- effects/internal/exponentialfadetransition.h | 4 +- effects/internal/fillleftrighteffect.h | 2 +- effects/internal/frei0reffect.cpp | 2 +- effects/internal/frei0reffect.h | 29 +- effects/internal/linearfadetransition.h | 4 +- effects/internal/logarithmicfadetransition.h | 4 +- effects/internal/paneffect.h | 2 +- effects/internal/shakeeffect.cpp | 7 +- effects/internal/shakeeffect.h | 2 +- effects/internal/solideffect.cpp | 4 +- effects/internal/solideffect.h | 2 +- effects/internal/texteffect.cpp | 6 +- effects/internal/texteffect.h | 2 +- effects/internal/timecodeeffect.cpp | 6 +- effects/internal/timecodeeffect.h | 2 +- effects/internal/toneeffect.cpp | 5 +- effects/internal/toneeffect.h | 2 +- effects/internal/transformeffect.cpp | 8 +- effects/internal/transformeffect.h | 2 +- effects/internal/voideffect.cpp | 2 +- effects/internal/voideffect.h | 2 +- effects/internal/volumeeffect.cpp | 2 +- effects/internal/volumeeffect.h | 2 +- effects/internal/vsthost.cpp | 4 +- effects/internal/vsthost.h | 4 +- {project => effects}/keyframe.cpp | 5 +- {project => effects}/keyframe.h | 18 +- effects/{ => shaders}/boxblur.frag | 0 effects/{ => shaders}/boxblur.xml | 0 effects/{ => shaders}/bulge.frag | 0 effects/{ => shaders}/bulge.xml | 0 effects/{ => shaders}/chromakey.frag | 0 effects/{ => shaders}/chromakey.xml | 0 .../{ => shaders}/chromaticaberration.frag | 0 effects/{ => shaders}/chromaticaberration.xml | 0 effects/{ => shaders}/colorcorrection.frag | 0 effects/{ => shaders}/colorcorrection.xml | 0 effects/{ => shaders}/colorsel.frag | 0 effects/{ => shaders}/colorsel.xml | 0 effects/{ => shaders}/common.frag | 0 effects/{ => shaders}/common.vert | 0 effects/{ => shaders}/crop.frag | 0 effects/{ => shaders}/crop.xml | 0 effects/{ => shaders}/crossstitch.frag | 0 effects/{ => shaders}/crossstitch.xml | 0 effects/{ => shaders}/directionalblur.frag | 0 effects/{ => shaders}/directionalblur.xml | 0 effects/{ => shaders}/dropshadow.xml.disabled | 0 effects/{ => shaders}/emboss.frag | 0 effects/{ => shaders}/emboss.xml | 0 effects/{ => shaders}/findedges.frag | 0 effects/{ => shaders}/findedges.xml.disabled | 0 effects/{ => shaders}/fisheye.frag | 0 effects/{ => shaders}/fisheye.xml | 0 effects/{ => shaders}/flip.frag | 0 effects/{ => shaders}/flip.xml | 0 effects/{ => shaders}/gaussianblur.frag | 0 effects/{ => shaders}/gaussianblur.xml | 0 effects/{ => shaders}/huesatbri.frag | 0 effects/{ => shaders}/huesatbri.xml | 0 effects/{ => shaders}/invert.frag | 0 effects/{ => shaders}/invert.xml | 0 effects/{ => shaders}/lumakey.frag | 0 effects/{ => shaders}/lumakey.xml | 0 effects/{ => shaders}/noise.frag | 0 effects/{ => shaders}/noise.xml | 0 effects/{ => shaders}/pixelate.frag | 0 effects/{ => shaders}/pixelate.xml | 0 effects/{ => shaders}/posterize.frag | 0 effects/{ => shaders}/posterize.xml | 0 effects/{ => shaders}/radialblur.frag | 0 effects/{ => shaders}/radialblur.xml | 0 effects/{ => shaders}/ripple.frag | 0 effects/{ => shaders}/ripple.xml | 0 effects/{ => shaders}/sphere.frag | 0 effects/{ => shaders}/sphere.xml | 0 effects/{ => shaders}/swirl.frag | 0 effects/{ => shaders}/swirl.xml | 0 effects/{ => shaders}/tile.frag | 0 effects/{ => shaders}/tile.xml | 0 effects/{ => shaders}/toonify.frag | 0 effects/{ => shaders}/toonify.xml | 0 effects/{ => shaders}/vignette.frag | 0 effects/{ => shaders}/vignette.xml | 0 effects/{ => shaders}/volumetriclight.frag | 0 effects/{ => shaders}/volumetriclight.xml | 0 effects/{ => shaders}/wave.frag | 0 effects/{ => shaders}/wave.xml | 0 {project => effects}/transition.cpp | 12 +- {project => effects}/transition.h | 0 {io => global}/config.cpp | 0 {io => global}/config.h | 0 {io => global}/crossplatformlib.cpp | 0 {io => global}/crossplatformlib.h | 0 debug.cpp => global/debug.cpp | 0 debug.h => global/debug.h | 0 oliveglobal.cpp => global/global.cpp | 12 +- oliveglobal.h => global/global.h | 2 +- {io => global}/math.cpp | 0 {io => global}/math.h | 0 {io => global}/path.cpp | 0 {io => global}/path.h | 0 io/qpainterwrapper.cpp | 61 ---- io/qpainterwrapper.h | 44 --- main.cpp | 14 +- olive.pro | 142 +++++---- panels/effectcontrols.cpp | 32 ++- panels/grapheditor.cpp | 22 +- panels/grapheditor.h | 2 +- panels/panels.cpp | 69 +---- panels/project.cpp | 15 +- panels/project.h | 2 +- panels/timeline.cpp | 12 +- panels/timeline.h | 6 +- panels/viewer.cpp | 24 +- panels/viewer.h | 2 +- {io => project}/clipboard.cpp | 10 +- {io => project}/clipboard.h | 2 +- project/effectfields.h | 14 - project/effectloaders.cpp | 271 ------------------ project/footage.cpp | 72 ++--- project/footage.h | 2 +- {io => project}/loadthread.cpp | 10 +- {io => project}/loadthread.h | 1 + project/media.cpp | 27 +- project/media.h | 2 +- {io => project}/previewgenerator.cpp | 6 +- {io => project}/previewgenerator.h | 0 project/projectelements.h | 7 - project/projectfilter.cpp | 22 +- project/projectmodel.cpp | 2 +- {io => project}/proxygenerator.cpp | 6 +- {io => project}/proxygenerator.h | 0 project/sourcescommon.cpp | 10 +- rendering/audio.cpp | 8 +- rendering/audio.h | 22 +- rendering/cacher.cpp | 4 +- {io => rendering}/exportthread.cpp | 10 +- {io => rendering}/exportthread.h | 0 rendering/renderfunctions.cpp | 12 +- rendering/renderfunctions.h | 5 +- rendering/renderthread.cpp | 2 +- rendering/renderthread.h | 4 +- {project => timeline}/clip.cpp | 14 +- {project => timeline}/clip.h | 8 +- {project => timeline}/marker.cpp | 10 +- {project => timeline}/marker.h | 0 {project => timeline}/selection.h | 0 {project => timeline}/sequence.cpp | 3 +- {project => timeline}/sequence.h | 7 +- ui/audiomonitor.cpp | 74 ++--- ui/collapsiblewidget.h | 2 +- ui/effectui.cpp | 23 +- ui/effectui.h | 7 +- ui/focusfilter.cpp | 2 +- ui/graphview.cpp | 15 +- ui/graphview.h | 4 +- ui/keyframenavigator.h | 3 +- ui/keyframeview.cpp | 12 +- ui/labelslider.cpp | 123 ++++---- ui/labelslider.h | 195 ++++++------- mainwindow.cpp => ui/mainwindow.cpp | 12 +- mainwindow.h => ui/mainwindow.h | 0 ui/menuhelper.cpp | 8 +- ui/scrollarea.cpp | 2 +- ui/sourceiconview.cpp | 74 ++--- ui/sourcetable.cpp | 60 ++-- ui/timelineheader.cpp | 8 +- ui/timelinewidget.cpp | 10 +- ui/timelinewidget.h | 6 +- ui/viewercontainer.cpp | 100 +++---- ui/viewerwidget.cpp | 8 +- ui/viewerwidget.h | 4 +- {project => undo}/comboaction.cpp | 0 {project => undo}/comboaction.h | 0 {project => undo}/undo.cpp | 39 ++- {project => undo}/undo.h | 23 +- 228 files changed, 1269 insertions(+), 1557 deletions(-) delete mode 100644 dialogs/speeddialog.ui delete mode 100644 effects/README rename {project => effects}/effect.cpp (96%) rename {project => effects}/effect.h (100%) rename {project/effectfields => effects}/effectfield.cpp (84%) rename {project/effectfields => effects}/effectfield.h (90%) create mode 100644 effects/effectfields.h rename {project => effects}/effectgizmo.cpp (100%) rename {project => effects}/effectgizmo.h (100%) create mode 100644 effects/effectloaders.cpp rename {project => effects}/effectloaders.h (100%) rename {project => effects}/effectrow.cpp (95%) rename {project => effects}/effectrow.h (100%) rename {project/effectfields => effects/fields}/boolfield.cpp (62%) rename {project/effectfields => effects/fields}/boolfield.h (78%) rename {project/effectfields => effects/fields}/buttonfield.cpp (100%) rename {project/effectfields => effects/fields}/buttonfield.h (88%) rename {project/effectfields => effects/fields}/colorfield.cpp (100%) rename {project/effectfields => effects/fields}/colorfield.h (90%) rename {project/effectfields => effects/fields}/combofield.cpp (100%) rename {project/effectfields => effects/fields}/combofield.h (89%) rename {project/effectfields => effects/fields}/doublefield.cpp (77%) rename {project/effectfields => effects/fields}/doublefield.h (87%) rename {project/effectfields => effects/fields}/filefield.cpp (100%) rename {project/effectfields => effects/fields}/filefield.h (87%) rename {project/effectfields => effects/fields}/fontfield.cpp (100%) rename {project/effectfields => effects/fields}/fontfield.h (88%) rename {project/effectfields => effects/fields}/labelfield.cpp (100%) rename {project/effectfields => effects/fields}/labelfield.h (85%) rename {project/effectfields => effects/fields}/stringfield.cpp (94%) rename {project/effectfields => effects/fields}/stringfield.h (87%) rename {project => effects}/keyframe.cpp (93%) rename {project => effects}/keyframe.h (81%) rename effects/{ => shaders}/boxblur.frag (100%) rename effects/{ => shaders}/boxblur.xml (100%) rename effects/{ => shaders}/bulge.frag (100%) rename effects/{ => shaders}/bulge.xml (100%) rename effects/{ => shaders}/chromakey.frag (100%) rename effects/{ => shaders}/chromakey.xml (100%) rename effects/{ => shaders}/chromaticaberration.frag (100%) rename effects/{ => shaders}/chromaticaberration.xml (100%) rename effects/{ => shaders}/colorcorrection.frag (100%) rename effects/{ => shaders}/colorcorrection.xml (100%) rename effects/{ => shaders}/colorsel.frag (100%) rename effects/{ => shaders}/colorsel.xml (100%) rename effects/{ => shaders}/common.frag (100%) rename effects/{ => shaders}/common.vert (100%) rename effects/{ => shaders}/crop.frag (100%) rename effects/{ => shaders}/crop.xml (100%) rename effects/{ => shaders}/crossstitch.frag (100%) rename effects/{ => shaders}/crossstitch.xml (100%) rename effects/{ => shaders}/directionalblur.frag (100%) rename effects/{ => shaders}/directionalblur.xml (100%) rename effects/{ => shaders}/dropshadow.xml.disabled (100%) rename effects/{ => shaders}/emboss.frag (100%) rename effects/{ => shaders}/emboss.xml (100%) rename effects/{ => shaders}/findedges.frag (100%) rename effects/{ => shaders}/findedges.xml.disabled (100%) rename effects/{ => shaders}/fisheye.frag (100%) rename effects/{ => shaders}/fisheye.xml (100%) rename effects/{ => shaders}/flip.frag (100%) rename effects/{ => shaders}/flip.xml (100%) rename effects/{ => shaders}/gaussianblur.frag (100%) rename effects/{ => shaders}/gaussianblur.xml (100%) rename effects/{ => shaders}/huesatbri.frag (100%) rename effects/{ => shaders}/huesatbri.xml (100%) rename effects/{ => shaders}/invert.frag (100%) rename effects/{ => shaders}/invert.xml (100%) rename effects/{ => shaders}/lumakey.frag (100%) rename effects/{ => shaders}/lumakey.xml (100%) rename effects/{ => shaders}/noise.frag (100%) rename effects/{ => shaders}/noise.xml (100%) rename effects/{ => shaders}/pixelate.frag (100%) rename effects/{ => shaders}/pixelate.xml (100%) rename effects/{ => shaders}/posterize.frag (100%) rename effects/{ => shaders}/posterize.xml (100%) rename effects/{ => shaders}/radialblur.frag (100%) rename effects/{ => shaders}/radialblur.xml (100%) rename effects/{ => shaders}/ripple.frag (100%) rename effects/{ => shaders}/ripple.xml (100%) rename effects/{ => shaders}/sphere.frag (100%) rename effects/{ => shaders}/sphere.xml (100%) rename effects/{ => shaders}/swirl.frag (100%) rename effects/{ => shaders}/swirl.xml (100%) rename effects/{ => shaders}/tile.frag (100%) rename effects/{ => shaders}/tile.xml (100%) rename effects/{ => shaders}/toonify.frag (100%) rename effects/{ => shaders}/toonify.xml (100%) rename effects/{ => shaders}/vignette.frag (100%) rename effects/{ => shaders}/vignette.xml (100%) rename effects/{ => shaders}/volumetriclight.frag (100%) rename effects/{ => shaders}/volumetriclight.xml (100%) rename effects/{ => shaders}/wave.frag (100%) rename effects/{ => shaders}/wave.xml (100%) rename {project => effects}/transition.cpp (92%) rename {project => effects}/transition.h (100%) rename {io => global}/config.cpp (100%) rename {io => global}/config.h (100%) rename {io => global}/crossplatformlib.cpp (100%) rename {io => global}/crossplatformlib.h (100%) rename debug.cpp => global/debug.cpp (100%) rename debug.h => global/debug.h (100%) rename oliveglobal.cpp => global/global.cpp (95%) rename oliveglobal.h => global/global.h (96%) rename {io => global}/math.cpp (100%) rename {io => global}/math.h (100%) rename {io => global}/path.cpp (100%) rename {io => global}/path.h (100%) delete mode 100644 io/qpainterwrapper.cpp delete mode 100644 io/qpainterwrapper.h rename {io => project}/clipboard.cpp (86%) rename {io => project}/clipboard.h (97%) delete mode 100644 project/effectfields.h delete mode 100644 project/effectloaders.cpp rename {io => project}/loadthread.cpp (99%) rename {io => project}/loadthread.h (98%) rename {io => project}/previewgenerator.cpp (96%) rename {io => project}/previewgenerator.h (100%) rename {io => project}/proxygenerator.cpp (96%) rename {io => project}/proxygenerator.h (100%) rename {io => rendering}/exportthread.cpp (96%) rename {io => rendering}/exportthread.h (100%) rename {project => timeline}/clip.cpp (95%) rename {project => timeline}/clip.h (92%) rename {project => timeline}/marker.cpp (93%) rename {project => timeline}/marker.h (100%) rename {project => timeline}/selection.h (100%) rename {project => timeline}/sequence.cpp (95%) rename {project => timeline}/sequence.h (89%) rename mainwindow.cpp => ui/mainwindow.cpp (97%) rename mainwindow.h => ui/mainwindow.h (100%) rename {project => undo}/comboaction.cpp (100%) rename {project => undo}/comboaction.h (100%) rename {project => undo}/undo.cpp (97%) rename {project => undo}/undo.h (98%) diff --git a/dialogs/advancedvideodialog.h b/dialogs/advancedvideodialog.h index 832e615ae..e393c062d 100644 --- a/dialogs/advancedvideodialog.h +++ b/dialogs/advancedvideodialog.h @@ -25,7 +25,7 @@ #include #include -#include "io/exportthread.h" +#include "rendering/exportthread.h" /** * @brief The AdvancedVideoDialog class diff --git a/dialogs/clippropertiesdialog.cpp b/dialogs/clippropertiesdialog.cpp index 6f4be32fe..a767e5dc6 100644 --- a/dialogs/clippropertiesdialog.cpp +++ b/dialogs/clippropertiesdialog.cpp @@ -5,7 +5,7 @@ #include #include "panels/panels.h" -#include "project/undo.h" +#include "undo/undo.h" ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clips) : QDialog(parent) @@ -33,8 +33,8 @@ ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clip layout->addWidget(new QLabel(tr("Duration:")), row, 0); duration_field_ = new LabelSlider(); - duration_field_->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); - duration_field_->set_minimum_value(1); + duration_field_->SetDisplayType(LabelSlider::FrameNumber); + duration_field_->SetMinimum(1); layout->addWidget(duration_field_, row, 1); row++; @@ -72,15 +72,15 @@ ClipPropertiesDialog::ClipPropertiesDialog(QWidget *parent, QVector clip } // it's assumed all the clips come from the same sequence - duration_field_->set_frame_rate(first_clip->sequence->frame_rate); + duration_field_->SetFrameRate(first_clip->sequence->frame_rate); if (all_clips_have_same_duration) { - duration_field_->set_default_value(first_clip->length()); - duration_field_->set_value(first_clip->length(), false); - duration_field_->set_maximum_value(first_clip->media_length()); + duration_field_->SetDefault(first_clip->length()); + duration_field_->SetValue(first_clip->length()); + duration_field_->SetMaximum(first_clip->media_length()); } else { - duration_field_->set_default_value(qSNaN()); - duration_field_->set_value(qSNaN(), false); + duration_field_->SetDefault(qSNaN()); + duration_field_->SetValue(qSNaN()); } } diff --git a/dialogs/clippropertiesdialog.h b/dialogs/clippropertiesdialog.h index 12b631b3f..8fd830978 100644 --- a/dialogs/clippropertiesdialog.h +++ b/dialogs/clippropertiesdialog.h @@ -4,7 +4,7 @@ #include #include -#include "project/clip.h" +#include "timeline/clip.h" #include "ui/labelslider.h" class ClipPropertiesDialog : public QDialog { diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index b37f6f4f2..7d48a49d4 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -30,13 +30,13 @@ #include #include -#include "oliveglobal.h" +#include "global/global.h" #include "dialogs/advancedvideodialog.h" #include "panels/panels.h" #include "ui/viewerwidget.h" #include "rendering/renderfunctions.h" -#include "io/exportthread.h" -#include "mainwindow.h" +#include "rendering/exportthread.h" +#include "ui/mainwindow.h" extern "C" { #include diff --git a/dialogs/exportdialog.h b/dialogs/exportdialog.h index 8daf27308..909912c55 100644 --- a/dialogs/exportdialog.h +++ b/dialogs/exportdialog.h @@ -29,9 +29,9 @@ #include #include -#include "project/sequence.h" +#include "timeline/sequence.h" -#include "io/exportthread.h" +#include "rendering/exportthread.h" class ExportDialog : public QDialog { diff --git a/dialogs/loaddialog.cpp b/dialogs/loaddialog.cpp index 310e668ca..92327eabb 100644 --- a/dialogs/loaddialog.cpp +++ b/dialogs/loaddialog.cpp @@ -24,12 +24,12 @@ #include #include -#include "oliveglobal.h" +#include "global/global.h" #include "panels/panels.h" #include "ui/sourcetable.h" -#include "mainwindow.h" +#include "ui/mainwindow.h" LoadDialog::LoadDialog(QWidget *parent, const QString& fn, bool autorecovery, bool clear) : QDialog(parent) diff --git a/dialogs/loaddialog.h b/dialogs/loaddialog.h index 285a58448..63586d226 100644 --- a/dialogs/loaddialog.h +++ b/dialogs/loaddialog.h @@ -26,7 +26,7 @@ #include #include "project/projectelements.h" -#include "io/loadthread.h" +#include "project/loadthread.h" class LoadDialog : public QDialog { diff --git a/dialogs/mediapropertiesdialog.cpp b/dialogs/mediapropertiesdialog.cpp index 8bcee21ed..dceb5ba9a 100644 --- a/dialogs/mediapropertiesdialog.cpp +++ b/dialogs/mediapropertiesdialog.cpp @@ -34,7 +34,7 @@ #include "project/footage.h" #include "project/media.h" #include "panels/project.h" -#include "project/undo.h" +#include "undo/undo.h" MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) : QDialog(parent), diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index b4b6e05a5..575775af7 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -22,9 +22,9 @@ #include "panels/panels.h" #include "panels/project.h" -#include "project/sequence.h" -#include "project/undo.h" -#include "project/clip.h" +#include "timeline/sequence.h" +#include "undo/undo.h" +#include "timeline/clip.h" #include "panels/timeline.h" #include "project/media.h" #include "rendering/audio.h" diff --git a/dialogs/newsequencedialog.h b/dialogs/newsequencedialog.h index ec7ab84b8..b71bdc099 100644 --- a/dialogs/newsequencedialog.h +++ b/dialogs/newsequencedialog.h @@ -28,7 +28,7 @@ #include "panels/project.h" #include "project/media.h" -#include "project/sequence.h" +#include "timeline/sequence.h" class NewSequenceDialog : public QDialog { diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 859ae57db..1ac93c362 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -20,12 +20,12 @@ #include "preferencesdialog.h" -#include "oliveglobal.h" -#include "io/config.h" -#include "io/path.h" +#include "global/global.h" +#include "global/config.h" +#include "global/path.h" #include "rendering/audio.h" #include "panels/panels.h" -#include "mainwindow.h" +#include "ui/mainwindow.h" #include #include diff --git a/dialogs/proxydialog.cpp b/dialogs/proxydialog.cpp index fb2641de1..bcc0a0745 100644 --- a/dialogs/proxydialog.cpp +++ b/dialogs/proxydialog.cpp @@ -28,9 +28,9 @@ #include #include -#include "io/proxygenerator.h" +#include "project/proxygenerator.h" #include "project/footage.h" -#include "mainwindow.h" +#include "ui/mainwindow.h" ProxyDialog::ProxyDialog(QWidget *parent, const QVector &media) : QDialog(parent), diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp index d2a9a87d7..bb8b73b33 100644 --- a/dialogs/replaceclipmediadialog.cpp +++ b/dialogs/replaceclipmediadialog.cpp @@ -23,7 +23,7 @@ #include "panels/panels.h" #include "rendering/cacher.h" -#include "project/undo.h" +#include "undo/undo.h" #include #include @@ -31,96 +31,96 @@ #include ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media) : - QDialog(parent), - media(old_media) + QDialog(parent), + media(old_media) { - setWindowTitle(tr("Replace clips using \"%1\"").arg(old_media->get_name())); + setWindowTitle(tr("Replace clips using \"%1\"").arg(old_media->get_name())); - resize(300, 400); + resize(300, 400); - QVBoxLayout* layout = new QVBoxLayout(this); + QVBoxLayout* layout = new QVBoxLayout(this); - layout->addWidget(new QLabel(tr("Select which media you want to replace this media's clips with:"), this)); + layout->addWidget(new QLabel(tr("Select which media you want to replace this media's clips with:"), this)); - tree = new QTreeView(this); + tree = new QTreeView(this); - layout->addWidget(tree); + layout->addWidget(tree); - use_same_media_in_points = new QCheckBox(tr("Keep the same media in-points"), this); - use_same_media_in_points->setChecked(true); - layout->addWidget(use_same_media_in_points); + use_same_media_in_points = new QCheckBox(tr("Keep the same media in-points"), this); + use_same_media_in_points->setChecked(true); + layout->addWidget(use_same_media_in_points); QHBoxLayout* buttons = new QHBoxLayout(); - buttons->addStretch(); + buttons->addStretch(); - QPushButton* replace_button = new QPushButton(tr("Replace"), this); - connect(replace_button, SIGNAL(clicked(bool)), this, SLOT(replace())); - buttons->addWidget(replace_button); + QPushButton* replace_button = new QPushButton(tr("Replace"), this); + connect(replace_button, SIGNAL(clicked(bool)), this, SLOT(replace())); + buttons->addWidget(replace_button); - QPushButton* cancel_button = new QPushButton(tr("Cancel"), this); - connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(close())); - buttons->addWidget(cancel_button); + QPushButton* cancel_button = new QPushButton(tr("Cancel"), this); + connect(cancel_button, SIGNAL(clicked(bool)), this, SLOT(close())); + buttons->addWidget(cancel_button); - buttons->addStretch(); + buttons->addStretch(); - layout->addLayout(buttons); + layout->addLayout(buttons); - tree->setModel(&olive::project_model); + tree->setModel(&olive::project_model); } void ReplaceClipMediaDialog::replace() { - QModelIndexList selected_items = tree->selectionModel()->selectedRows(); - if (selected_items.size() != 1) { - QMessageBox::critical( - this, - tr("No media selected"), - tr("Please select a media to replace with or click 'Cancel'."), - QMessageBox::Ok - ); - } else { + QModelIndexList selected_items = tree->selectionModel()->selectedRows(); + if (selected_items.size() != 1) { + QMessageBox::critical( + this, + tr("No media selected"), + tr("Please select a media to replace with or click 'Cancel'."), + QMessageBox::Ok + ); + } else { Media* new_item = static_cast(selected_items.at(0).internalPointer()); - if (media == new_item) { - QMessageBox::critical( - this, - tr("Same media selected"), - tr("You selected the same media that you're replacing. Please select a different one or click 'Cancel'."), - QMessageBox::Ok - ); - } else if (new_item->get_type() == MEDIA_TYPE_FOLDER) { - QMessageBox::critical( - this, - tr("Folder selected"), - tr("You cannot replace footage with a folder."), - QMessageBox::Ok - ); - } else { - if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && olive::ActiveSequence == new_item->to_sequence()) { - QMessageBox::critical( - this, - tr("Active sequence selected"), - tr("You cannot insert a sequence into itself."), - QMessageBox::Ok - ); - } else { - ReplaceClipMediaCommand* rcmc = new ReplaceClipMediaCommand( - media, - new_item, - use_same_media_in_points->isChecked() - ); + if (media == new_item) { + QMessageBox::critical( + this, + tr("Same media selected"), + tr("You selected the same media that you're replacing. Please select a different one or click 'Cancel'."), + QMessageBox::Ok + ); + } else if (new_item->get_type() == MEDIA_TYPE_FOLDER) { + QMessageBox::critical( + this, + tr("Folder selected"), + tr("You cannot replace footage with a folder."), + QMessageBox::Ok + ); + } else { + if (new_item->get_type() == MEDIA_TYPE_SEQUENCE && olive::ActiveSequence == new_item->to_sequence()) { + QMessageBox::critical( + this, + tr("Active sequence selected"), + tr("You cannot insert a sequence into itself."), + QMessageBox::Ok + ); + } else { + ReplaceClipMediaCommand* rcmc = new ReplaceClipMediaCommand( + media, + new_item, + use_same_media_in_points->isChecked() + ); - for (int i=0;iclips.size();i++) { + for (int i=0;iclips.size();i++) { ClipPtr c = olive::ActiveSequence->clips.at(i); if (c != nullptr && c->media() == media) { - rcmc->clips.append(c); - } - } + rcmc->clips.append(c); + } + } - olive::UndoStack.push(rcmc); + olive::UndoStack.push(rcmc); - close(); - } + close(); + } - } - } + } + } } diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index c2233fa9d..b7727e048 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -26,13 +26,13 @@ #include #include -#include "project/sequence.h" +#include "timeline/sequence.h" #include "project/footage.h" #include "rendering/renderfunctions.h" #include "panels/panels.h" #include "panels/timeline.h" -#include "project/undo.h" -#include "project/effect.h" +#include "undo/undo.h" +#include "effects/effect.h" #include "project/media.h" SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent) { @@ -47,20 +47,20 @@ SpeedDialog::SpeedDialog(QWidget *parent, QVector clips) : QDialog(parent grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0); percent = new LabelSlider(this); - percent->decimal_places = 2; - percent->set_display_type(LabelSlider::LABELSLIDER_PERCENT); - percent->set_default_value(1); + percent->SetDecimalPlaces(2); + percent->SetDisplayType(LabelSlider::Percent); + percent->SetDefault(1); grid->addWidget(percent, 0, 1); grid->addWidget(new QLabel(tr("Frame Rate:"), this), 1, 0); frame_rate = new LabelSlider(this); - frame_rate->decimal_places = 3; + frame_rate->SetDecimalPlaces(3); grid->addWidget(frame_rate, 1, 1); grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0); duration = new LabelSlider(this); - duration->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); - duration->set_frame_rate(olive::ActiveSequence->frame_rate); + duration->SetDisplayType(LabelSlider::FrameNumber); + duration->SetFrameRate(olive::ActiveSequence->frame_rate); grid->addWidget(duration, 2, 1); main_layout->addLayout(grid); @@ -168,16 +168,16 @@ void SpeedDialog::run() { } } - frame_rate->set_minimum_value(1); - percent->set_minimum_value(0.0001); - duration->set_minimum_value(1); + frame_rate->SetMinimum(1); + percent->SetMinimum(0.0001); + duration->SetMinimum(1); frame_rate->setEnabled(enable_frame_rate); - frame_rate->set_default_value(default_frame_rate); - frame_rate->set_value(current_frame_rate, false); - percent->set_value(current_percent, false); - duration->set_default_value(default_length); - duration->set_value((current_length == -1) ? qSNaN() : current_length, false); + frame_rate->SetDefault(default_frame_rate); + frame_rate->SetValue(current_frame_rate); + percent->SetValue(current_percent); + duration->SetDefault(default_length); + duration->SetValue((current_length == -1) ? qSNaN() : current_length); exec(); } @@ -213,8 +213,8 @@ void SpeedDialog::percent_update() { } } - frame_rate->set_value(fr_val, false); - duration->set_value((len_val == -1) ? qSNaN() : len_val, false); + frame_rate->SetValue(fr_val); + duration->SetValue((len_val == -1) ? qSNaN() : len_val); } void SpeedDialog::duration_update() { @@ -248,8 +248,8 @@ void SpeedDialog::duration_update() { } } - frame_rate->set_value(fr_val, false); - percent->set_value(pc_val, false); + frame_rate->SetValue(fr_val); + percent->SetValue(pc_val); } void SpeedDialog::frame_rate_update() { @@ -312,8 +312,8 @@ void SpeedDialog::frame_rate_update() { } } - percent->set_value(pc_val, false); - duration->set_value((len_val == -1) ? qSNaN() : len_val, false); + percent->SetValue(pc_val); + duration->SetValue((len_val == -1) ? qSNaN() : len_val); } void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, long& lr) { @@ -321,7 +321,7 @@ void set_speed(ComboAction* ca, Clip* c, double speed, bool ripple, long& ep, lo long proposed_out = c->timeline_out(); double multiplier = (c->speed().value / speed); - proposed_out = c->timeline_in() + (c->length() * multiplier); + proposed_out = qRound(c->timeline_in() + (c->length() * multiplier)); ca->append(new SetSpeedAction(c, speed)); if (!ripple && proposed_out > c->timeline_out()) { for (int i=0;isequence->clips.size();i++) { diff --git a/dialogs/speeddialog.h b/dialogs/speeddialog.h index 26bb0ab9c..ac68c51dc 100644 --- a/dialogs/speeddialog.h +++ b/dialogs/speeddialog.h @@ -24,7 +24,7 @@ #include #include -#include "project/clip.h" +#include "timeline/clip.h" #include "ui/labelslider.h" class SpeedDialog : public QDialog diff --git a/dialogs/speeddialog.ui b/dialogs/speeddialog.ui deleted file mode 100644 index 144e418a4..000000000 --- a/dialogs/speeddialog.ui +++ /dev/null @@ -1,107 +0,0 @@ - - - SpeedDialog - - - - 0 - 0 - 400 - 300 - - - - Dialog - - - - - 30 - 240 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 20 - 20 - 47 - 13 - - - - Speed: - - - - - - 20 - 50 - 47 - 13 - - - - Frame Rate: - - - - - - 20 - 80 - 47 - 13 - - - - Duration: - - - - - - - buttonBox - accepted() - SpeedDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - SpeedDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/effects/README b/effects/README deleted file mode 100644 index 71a3822d3..000000000 --- a/effects/README +++ /dev/null @@ -1 +0,0 @@ -Place this folder in the runtime folder of Olive. \ No newline at end of file diff --git a/project/effect.cpp b/effects/effect.cpp similarity index 96% rename from project/effect.cpp rename to effects/effect.cpp index 43d2e2ec2..799aa3538 100644 --- a/project/effect.cpp +++ b/effects/effect.cpp @@ -25,19 +25,19 @@ #include "ui/viewerwidget.h" #include "ui/collapsiblewidget.h" #include "panels/project.h" -#include "project/undo.h" -#include "project/sequence.h" -#include "project/clip.h" +#include "undo/undo.h" +#include "timeline/sequence.h" +#include "timeline/clip.h" #include "panels/timeline.h" #include "panels/effectcontrols.h" #include "panels/grapheditor.h" #include "ui/checkboxex.h" -#include "debug.h" -#include "io/path.h" -#include "mainwindow.h" -#include "io/math.h" -#include "io/clipboard.h" -#include "io/config.h" +#include "global/debug.h" +#include "global/path.h" +#include "ui/mainwindow.h" +#include "global/math.h" +#include "project/clipboard.h" +#include "global/config.h" #include "transition.h" #include "effects/internal/transformeffect.h" diff --git a/project/effect.h b/effects/effect.h similarity index 100% rename from project/effect.h rename to effects/effect.h diff --git a/project/effectfields/effectfield.cpp b/effects/effectfield.cpp similarity index 84% rename from project/effectfields/effectfield.cpp rename to effects/effectfield.cpp index 0fe9421a1..73aabc02d 100644 --- a/project/effectfields/effectfield.cpp +++ b/effects/effectfield.cpp @@ -33,18 +33,18 @@ #include "rendering/renderfunctions.h" -#include "io/config.h" +#include "global/config.h" -#include "project/effectrow.h" -#include "project/effect.h" +#include "effects/effectrow.h" +#include "effects/effect.h" -#include "project/undo.h" -#include "project/clip.h" -#include "project/sequence.h" +#include "undo/undo.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" -#include "io/math.h" +#include "global/math.h" -#include "debug.h" +#include "global/debug.h" EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) : QObject(parent), @@ -100,10 +100,10 @@ QWidget *EffectField::CreateWidget() return new QLabel(tr("(Invalid field)")); } +void EffectField::UpdateWidgetValue(QWidget *, double) {} + QVariant EffectField::GetValueAt(double timecode) { - Q_ASSERT(!keyframes.isEmpty()); - if (HasKeyframes()) { int before_keyframe; int after_keyframe; @@ -179,7 +179,8 @@ QVariant EffectField::GetValueAt(double timecode) } } - return value; + perpetual_data_ = value; + break; } case EFFECT_FIELD_COLOR: { @@ -191,32 +192,27 @@ QVariant EffectField::GetValueAt(double timecode) QColor after_data = keyframes.at(after_keyframe).data.value(); 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)); } - return value; + perpetual_data_ = value; + break; } case EFFECT_FIELD_STRING: case EFFECT_FIELD_BOOL: case EFFECT_FIELD_COMBO: case EFFECT_FIELD_FONT: case EFFECT_FIELD_FILE: - return before_data; + perpetual_data_ = before_data; + break; default: break; } } - return keyframes.first().data; + return perpetual_data_; } void EffectField::SetValueAt(double time, const QVariant &value) { - if (keyframes.isEmpty()) { - EffectKeyframe key; - key.data = value; - keyframes.append(key); - return; - } - - if (GetParentRow()->IsKeyframing()) { + if (HasKeyframes()) { // Create keyframe here @@ -237,6 +233,7 @@ void EffectField::SetValueAt(double time, const QVariant &value) EffectKeyframe key; key.time = frame_timecode; key.data = value; + key.type = (keyframes.isEmpty()) ? EFFECT_KEYFRAME_LINEAR : keyframes.last().type; keyframes.append(key); } else { EffectKeyframe& key = keyframes[keyframe_index]; @@ -244,7 +241,7 @@ void EffectField::SetValueAt(double time, const QVariant &value) } } else { - keyframes.first().data = value; + perpetual_data_ = value; } emit Changed(); @@ -256,23 +253,37 @@ double EffectField::Now() return playhead_to_clip_seconds(c, c->sequence->playhead); } +long EffectField::NowInFrames() +{ + Clip* c = GetParentRow()->GetParentEffect()->parent_clip; + return playhead_to_clip_frame(c, c->sequence->playhead); +} + void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) { if (enabled) { - // Convert "perpetual" keyframe to a keyframe at this time - ca->append(new SetLong(&keyframes.first().time, keyframes.first().time, timecodeToFrame(Now()))); + // Create keyframe from perpetual data + EffectKeyframe key; + + key.time = NowInFrames(); + key.data = perpetual_data_; + key.type = EFFECT_KEYFRAME_LINEAR; + + keyframes.append(key); + + ca->append(new KeyframeAdd(this, keyframes.size()-1)); } else { // Convert keyframes to one "perpetual" keyframe // Set first keyframe to whatever the data is now - ca->append(new SetQVariant(&keyframes.first().data, keyframes.first().data, GetValueAt(Now()))); + ca->append(new SetQVariant(&perpetual_data_, perpetual_data_, GetValueAt(Now()))); - // Delete all keyframes except the first - for (int i=1;iappend(new KeyframeDelete(this, 1)); + // Delete all keyframes + for (int i=0;iappend(new KeyframeDelete(this, 0)); } } @@ -379,33 +390,9 @@ void EffectField::get_keyframe_data(double timecode, int &before, int &after, do } bool EffectField::HasKeyframes() { - return (GetParentRow()->IsKeyframing() && keyframes.size() > 1); + return (GetParentRow()->IsKeyframing() && !keyframes.isEmpty()); } -/* -void EffectField::ui_element_change() { - // TODO address this - //bool dragging_double = (type_ == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); - bool dragging_double = false; - ComboAction* ca = nullptr; - if (!dragging_double) ca = new ComboAction(); - //make_key_from_change(ca); - if (!dragging_double) olive::UndoStack.push(ca); - emit Changed(); -} -*/ - -/* -void EffectField::make_key_from_change(ComboAction* ca) { - if (GetParentRow()->isKeyframing()) { - GetParentRow()->set_keyframe_now(ca); - } else if (ca != nullptr) { - // set undo - ca->append(new EffectFieldUndo(this)); - } -} -*/ - bool EffectField::IsEnabled() { return enabled_; } diff --git a/project/effectfields/effectfield.h b/effects/effectfield.h similarity index 90% rename from project/effectfields/effectfield.h rename to effects/effectfield.h index 08fce79bb..f8f824896 100644 --- a/project/effectfields/effectfield.h +++ b/effects/effectfield.h @@ -25,7 +25,7 @@ #include #include -#include "project/keyframe.h" +#include "effects/keyframe.h" class EffectRow; class ComboAction; @@ -56,6 +56,7 @@ public: void SetValueAt(double time, const QVariant& value); double Now(); + long NowInFrames(); void PrepareDataForKeyframing(bool enabled, ComboAction* ca); @@ -66,6 +67,7 @@ public: virtual QString ConvertValueToString(const QVariant& v); virtual QWidget* CreateWidget(); + virtual void UpdateWidgetValue(QWidget* widget, double); double GetValidKeyframeHandlePosition(int key, bool post); @@ -92,6 +94,7 @@ private: bool enabled_; int colspan_; + QVariant perpetual_data_; }; #endif // EFFECTFIELD_H diff --git a/effects/effectfields.h b/effects/effectfields.h new file mode 100644 index 000000000..1c8e687e2 --- /dev/null +++ b/effects/effectfields.h @@ -0,0 +1,14 @@ +#ifndef EFFECTFIELDS_H +#define EFFECTFIELDS_H + +#include "fields/boolfield.h" +#include "fields/buttonfield.h" +#include "fields/colorfield.h" +#include "fields/combofield.h" +#include "fields/doublefield.h" +#include "fields/filefield.h" +#include "fields/fontfield.h" +#include "fields/labelfield.h" +#include "fields/stringfield.h" + +#endif // EFFECTFIELDS_H diff --git a/project/effectgizmo.cpp b/effects/effectgizmo.cpp similarity index 100% rename from project/effectgizmo.cpp rename to effects/effectgizmo.cpp diff --git a/project/effectgizmo.h b/effects/effectgizmo.h similarity index 100% rename from project/effectgizmo.h rename to effects/effectgizmo.h diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp new file mode 100644 index 000000000..d00c8b67b --- /dev/null +++ b/effects/effectloaders.cpp @@ -0,0 +1,271 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "effectloaders.h" + +#include "effects/effect.h" +#include "effects/transition.h" +#include "global/path.h" +#include "panels/panels.h" +#include "panels/effectcontrols.h" +#include "global/crossplatformlib.h" +#include "global/config.h" + +#include +#include + +#include + +#ifndef NOFREI0R +#include +typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info); +#endif + +void load_internal_effects() { + if (!olive::CurrentRuntimeConfig.shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional"; + + EffectMeta em; + + // load internal effects + em.path = ":/internalshaders"; + + em.type = EFFECT_TYPE_EFFECT; + em.subtype = EFFECT_TYPE_AUDIO; + + em.name = "Volume"; + em.internal = EFFECT_INTERNAL_VOLUME; + effects.append(em); + + em.name = "Pan"; + em.internal = EFFECT_INTERNAL_PAN; + effects.append(em); + +#ifndef NOVST + em.name = "VST Plugin 2.x"; + em.internal = EFFECT_INTERNAL_VST; + effects.append(em); +#endif + + em.name = "Tone"; + em.internal = EFFECT_INTERNAL_TONE; + effects.append(em); + + em.name = "Noise"; + em.internal = EFFECT_INTERNAL_NOISE; + effects.append(em); + + em.name = "Fill Left/Right"; + em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT; + effects.append(em); + + em.subtype = EFFECT_TYPE_VIDEO; + + em.name = "Transform"; + em.category = "Distort"; + em.internal = EFFECT_INTERNAL_TRANSFORM; + effects.append(em); + + em.name = "Corner Pin"; + em.internal = EFFECT_INTERNAL_CORNERPIN; + effects.append(em); + + /*em.name = "Mask"; + em.internal = EFFECT_INTERNAL_MASK; + effects.append(em);*/ + + em.name = "Shake"; + em.internal = EFFECT_INTERNAL_SHAKE; + effects.append(em); + + em.name = "Text"; + em.category = "Render"; + em.internal = EFFECT_INTERNAL_TEXT; + effects.append(em); + + em.name = "Timecode"; + em.internal = EFFECT_INTERNAL_TIMECODE; + effects.append(em); + + em.name = "Solid"; + em.internal = EFFECT_INTERNAL_SOLID; + effects.append(em); + + // internal transitions + em.type = EFFECT_TYPE_TRANSITION; + em.category = ""; + + em.name = "Cross Dissolve"; + em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE; + effects.append(em); + + em.subtype = EFFECT_TYPE_AUDIO; + + em.name = "Linear Fade"; + em.internal = TRANSITION_INTERNAL_LINEARFADE; + effects.append(em); + + em.name = "Exponential Fade"; + em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE; + effects.append(em); + + em.name = "Logarithmic Fade"; + em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE; + effects.append(em); +} + +void load_shader_effects() { + QList effects_paths = get_effects_paths(); + + for (int h=0;h entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); + for (int i=0;istart(); +} + +#ifndef NOFREI0R +void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector& loaded_names) { + QDir search_dir(dir); + if (search_dir.exists()) { + QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info")); + if (get_info_func != nullptr) { + f0r_plugin_info_t info; + get_info_func(&info); + + if (!loaded_names.contains(info.name) + && info.plugin_type == F0R_PLUGIN_TYPE_FILTER + && info.color_model == F0R_COLOR_MODEL_RGBA8888) { + em.name = info.name; + em.path = dir; + em.filename = entry_list.at(j); + em.tooltip = QString("%1\n%2\n%3\n%4").arg(em.name, info.author, info.explanation, em.filename); + + loaded_names.append(em.name); + + effects.append(em); + } +// qDebug() << "Found:" << info.name << "by" << info.author; + } + LibClose(effect); + } +// qDebug() << search_dir.filePath(entry_list.at(j)); + } + } + } +} + +void load_frei0r_effects() { + QList effect_dirs = get_effects_paths(); + + // add defined paths for frei0r plugins on unix +#if defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__) + effect_dirs.prepend("/usr/lib/frei0r-1"); + effect_dirs.prepend("/usr/local/lib/frei0r-1"); + effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib"); +#endif + + QString env_path(qgetenv("FREI0R_PATH")); + if (!env_path.isEmpty()) effect_dirs.append(env_path); + + QVector loaded_names; + + // search for paths + EffectMeta em; + em.category = "Frei0r"; + em.type = EFFECT_TYPE_EFFECT; + em.subtype = EFFECT_TYPE_VIDEO; + em.internal = EFFECT_INTERNAL_FREI0R; + + for (int i=0;ieffects_loaded.lock(); +} + +void EffectInit::run() { + qInfo() << "Initializing effects..."; + load_internal_effects(); + load_shader_effects(); +#ifndef NOFREI0R + load_frei0r_effects(); +#endif + panel_effect_controls->effects_loaded.unlock(); + qInfo() << "Finished initializing effects"; +} diff --git a/project/effectloaders.h b/effects/effectloaders.h similarity index 100% rename from project/effectloaders.h rename to effects/effectloaders.h diff --git a/project/effectrow.cpp b/effects/effectrow.cpp similarity index 95% rename from project/effectrow.cpp rename to effects/effectrow.cpp index a1337fb7b..16cfde39d 100644 --- a/project/effectrow.cpp +++ b/effects/effectrow.cpp @@ -24,9 +24,9 @@ #include #include -#include "project/undo.h" -#include "project/clip.h" -#include "project/sequence.h" +#include "undo/undo.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" #include "panels/panels.h" #include "panels/effectcontrols.h" #include "panels/viewer.h" diff --git a/project/effectrow.h b/effects/effectrow.h similarity index 100% rename from project/effectrow.h rename to effects/effectrow.h diff --git a/project/effectfields/boolfield.cpp b/effects/fields/boolfield.cpp similarity index 62% rename from project/effectfields/boolfield.cpp rename to effects/fields/boolfield.cpp index 0a15030c4..f7f4d70ac 100644 --- a/project/effectfields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -22,6 +22,20 @@ QWidget *BoolField::CreateWidget() return cb; } +void BoolField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + QCheckBox* cb = static_cast(widget); + + // Setting the checked state on the checkbox below normally triggers a change() signal that will then trickle back + // to setting a value on this field. Therefore we block its signals while we're setting this. + + cb->blockSignals(true); + + cb->setChecked(GetBoolAt(timecode)); + + cb->blockSignals(false); +} + QVariant BoolField::ConvertStringToValue(const QString &s) { return (s == "1"); diff --git a/project/effectfields/boolfield.h b/effects/fields/boolfield.h similarity index 78% rename from project/effectfields/boolfield.h rename to effects/fields/boolfield.h index bf6be11d7..0ac09a01e 100644 --- a/project/effectfields/boolfield.h +++ b/effects/fields/boolfield.h @@ -1,7 +1,7 @@ #ifndef BOOLFIELD_H #define BOOLFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class BoolField : public EffectField { @@ -12,6 +12,7 @@ public: bool GetBoolAt(double timecode); virtual QWidget* CreateWidget() override; + virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; virtual QVariant ConvertStringToValue(const QString& s) override; virtual QString ConvertValueToString(const QVariant& v) override; diff --git a/project/effectfields/buttonfield.cpp b/effects/fields/buttonfield.cpp similarity index 100% rename from project/effectfields/buttonfield.cpp rename to effects/fields/buttonfield.cpp diff --git a/project/effectfields/buttonfield.h b/effects/fields/buttonfield.h similarity index 88% rename from project/effectfields/buttonfield.h rename to effects/fields/buttonfield.h index 71e77f1ac..c3e3150f7 100644 --- a/project/effectfields/buttonfield.h +++ b/effects/fields/buttonfield.h @@ -1,7 +1,7 @@ #ifndef BUTTONFIELD_H #define BUTTONFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class ButtonField : public EffectField { diff --git a/project/effectfields/colorfield.cpp b/effects/fields/colorfield.cpp similarity index 100% rename from project/effectfields/colorfield.cpp rename to effects/fields/colorfield.cpp diff --git a/project/effectfields/colorfield.h b/effects/fields/colorfield.h similarity index 90% rename from project/effectfields/colorfield.h rename to effects/fields/colorfield.h index f4ef25020..7c6d60216 100644 --- a/project/effectfields/colorfield.h +++ b/effects/fields/colorfield.h @@ -1,7 +1,7 @@ #ifndef COLORFIELD_H #define COLORFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class ColorField : public EffectField { diff --git a/project/effectfields/combofield.cpp b/effects/fields/combofield.cpp similarity index 100% rename from project/effectfields/combofield.cpp rename to effects/fields/combofield.cpp diff --git a/project/effectfields/combofield.h b/effects/fields/combofield.h similarity index 89% rename from project/effectfields/combofield.h rename to effects/fields/combofield.h index c886a0172..bdf5a9972 100644 --- a/project/effectfields/combofield.h +++ b/effects/fields/combofield.h @@ -1,7 +1,7 @@ #ifndef COMBOFIELD_H #define COMBOFIELD_H -#include "effectfield.h" +#include "../effectfield.h" struct ComboFieldItem { QString name; diff --git a/project/effectfields/doublefield.cpp b/effects/fields/doublefield.cpp similarity index 77% rename from project/effectfields/doublefield.cpp rename to effects/fields/doublefield.cpp index 63de39fbb..8499c2f9b 100644 --- a/project/effectfields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -1,11 +1,13 @@ #include "doublefield.h" +#include + DoubleField::DoubleField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_DOUBLE), min_(qSNaN()), max_(qSNaN()), default_(0), - display_type_(LabelSlider::LABELSLIDER_NORMAL), + display_type_(LabelSlider::Normal), frame_rate_(30), value_set_(false) { @@ -62,14 +64,14 @@ QWidget *DoubleField::CreateWidget() LabelSlider* ls = new LabelSlider(); if (!qIsNaN(min_)) { - ls->set_minimum_value(min_); + ls->SetMinimum(min_); } - ls->set_default_value(default_); + ls->SetDefault(default_); if (!qIsNaN(max_)) { - ls->set_maximum_value(max_); + ls->SetMaximum(max_); } - ls->set_display_type(display_type_); - ls->set_frame_rate(frame_rate_); + ls->SetDisplayType(display_type_); + ls->SetFrameRate(frame_rate_); ls->setEnabled(IsEnabled()); @@ -80,6 +82,11 @@ QWidget *DoubleField::CreateWidget() return ls; } +void DoubleField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + static_cast(widget)->SetValue(GetDoubleAt(timecode)); +} + void DoubleField::ValueHasBeenSet() { value_set_ = true; diff --git a/project/effectfields/doublefield.h b/effects/fields/doublefield.h similarity index 87% rename from project/effectfields/doublefield.h rename to effects/fields/doublefield.h index 2935cf4d6..39a46a334 100644 --- a/project/effectfields/doublefield.h +++ b/effects/fields/doublefield.h @@ -1,7 +1,7 @@ #ifndef DOUBLEFIELD_H #define DOUBLEFIELD_H -#include "effectfield.h" +#include "../effectfield.h" #include "ui/labelslider.h" class DoubleField : public EffectField @@ -36,6 +36,7 @@ public: virtual QString ConvertValueToString(const QVariant& v); virtual QWidget* CreateWidget() override; + virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; private: double min_; double max_; diff --git a/project/effectfields/filefield.cpp b/effects/fields/filefield.cpp similarity index 100% rename from project/effectfields/filefield.cpp rename to effects/fields/filefield.cpp diff --git a/project/effectfields/filefield.h b/effects/fields/filefield.h similarity index 87% rename from project/effectfields/filefield.h rename to effects/fields/filefield.h index 2a68a0b50..ef1e1e099 100644 --- a/project/effectfields/filefield.h +++ b/effects/fields/filefield.h @@ -1,7 +1,7 @@ #ifndef FILEFIELD_H #define FILEFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class FileField : public EffectField { diff --git a/project/effectfields/fontfield.cpp b/effects/fields/fontfield.cpp similarity index 100% rename from project/effectfields/fontfield.cpp rename to effects/fields/fontfield.cpp diff --git a/project/effectfields/fontfield.h b/effects/fields/fontfield.h similarity index 88% rename from project/effectfields/fontfield.h rename to effects/fields/fontfield.h index b2a828b1d..ddd2b05be 100644 --- a/project/effectfields/fontfield.h +++ b/effects/fields/fontfield.h @@ -1,7 +1,7 @@ #ifndef FONTFIELD_H #define FONTFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class FontField : public EffectField { Q_OBJECT diff --git a/project/effectfields/labelfield.cpp b/effects/fields/labelfield.cpp similarity index 100% rename from project/effectfields/labelfield.cpp rename to effects/fields/labelfield.cpp diff --git a/project/effectfields/labelfield.h b/effects/fields/labelfield.h similarity index 85% rename from project/effectfields/labelfield.h rename to effects/fields/labelfield.h index 628a9181a..31a40462b 100644 --- a/project/effectfields/labelfield.h +++ b/effects/fields/labelfield.h @@ -1,7 +1,7 @@ #ifndef LABELFIELD_H #define LABELFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class LabelField : public EffectField { diff --git a/project/effectfields/stringfield.cpp b/effects/fields/stringfield.cpp similarity index 94% rename from project/effectfields/stringfield.cpp rename to effects/fields/stringfield.cpp index 105e5c28f..b2f38a246 100644 --- a/project/effectfields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -3,7 +3,7 @@ #include #include "ui/texteditex.h" -#include "io/config.h" +#include "global/config.h" StringField::StringField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_STRING) diff --git a/project/effectfields/stringfield.h b/effects/fields/stringfield.h similarity index 87% rename from project/effectfields/stringfield.h rename to effects/fields/stringfield.h index 043dbbb67..4643f7bd6 100644 --- a/project/effectfields/stringfield.h +++ b/effects/fields/stringfield.h @@ -1,7 +1,7 @@ #ifndef STRINGFIELD_H #define STRINGFIELD_H -#include "effectfield.h" +#include "../effectfield.h" class StringField : public EffectField { diff --git a/effects/internal/audionoiseeffect.h b/effects/internal/audionoiseeffect.h index f2668d354..dab29be78 100644 --- a/effects/internal/audionoiseeffect.h +++ b/effects/internal/audionoiseeffect.h @@ -21,7 +21,7 @@ #ifndef AUDIONOISEEFFECT_H #define AUDIONOISEEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class AudioNoiseEffect : public Effect { Q_OBJECT diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index 566247109..a80a504ef 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -20,9 +20,9 @@ #include "cornerpineffect.h" -#include "io/path.h" -#include "project/clip.h" -#include "debug.h" +#include "global/path.h" +#include "timeline/clip.h" +#include "global/debug.h" CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { SetFlags(Effect::CoordsFlag & Effect::ShaderFlag); diff --git a/effects/internal/cornerpineffect.h b/effects/internal/cornerpineffect.h index 5b2460ef8..ffee7311b 100644 --- a/effects/internal/cornerpineffect.h +++ b/effects/internal/cornerpineffect.h @@ -21,7 +21,7 @@ #ifndef CORNERPINEFFECT_H #define CORNERPINEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class CornerPinEffect : public Effect { Q_OBJECT diff --git a/effects/internal/crossdissolvetransition.h b/effects/internal/crossdissolvetransition.h index 2b11b7c7e..42c91492e 100644 --- a/effects/internal/crossdissolvetransition.h +++ b/effects/internal/crossdissolvetransition.h @@ -21,7 +21,7 @@ #ifndef CROSSDISSOLVETRANSITION_H #define CROSSDISSOLVETRANSITION_H -#include "project/transition.h" +#include "effects/transition.h" class CrossDissolveTransition : public Transition { public: diff --git a/effects/internal/cubetransition.h b/effects/internal/cubetransition.h index 82519ad03..fb3bdc512 100644 --- a/effects/internal/cubetransition.h +++ b/effects/internal/cubetransition.h @@ -21,7 +21,7 @@ #ifndef CUBETRANSITION_H #define CUBETRANSITION_H -#include "project/transition.h" +#include "effects/transition.h" class CubeTransition : public Transition { public: diff --git a/effects/internal/exponentialfadetransition.h b/effects/internal/exponentialfadetransition.h index 36ec7f6f1..8aeaccdc0 100644 --- a/effects/internal/exponentialfadetransition.h +++ b/effects/internal/exponentialfadetransition.h @@ -21,12 +21,12 @@ #ifndef EXPONENTIALFADETRANSITION_H #define EXPONENTIALFADETRANSITION_H -#include "project/transition.h" +#include "effects/transition.h" class ExponentialFadeTransition : public Transition { public: ExponentialFadeTransition(Clip* c, Clip* s, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); }; #endif // LINEARFADETRANSITION_H diff --git a/effects/internal/fillleftrighteffect.h b/effects/internal/fillleftrighteffect.h index 6a47a31ac..9300bcb72 100644 --- a/effects/internal/fillleftrighteffect.h +++ b/effects/internal/fillleftrighteffect.h @@ -21,7 +21,7 @@ #ifndef FILLLEFTRIGHTEFFECT_H #define FILLLEFTRIGHTEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class FillLeftRightEffect : public Effect { Q_OBJECT diff --git a/effects/internal/frei0reffect.cpp b/effects/internal/frei0reffect.cpp index da45e4564..c63514e03 100644 --- a/effects/internal/frei0reffect.cpp +++ b/effects/internal/frei0reffect.cpp @@ -25,7 +25,7 @@ #include #include -#include "project/clip.h" +#include "timeline/clip.h" typedef f0r_instance_t (*f0rConstructFunc)(unsigned int width, unsigned int height); typedef int (*f0rInitFunc) (); diff --git a/effects/internal/frei0reffect.h b/effects/internal/frei0reffect.h index b6428a8b9..6f7356b28 100644 --- a/effects/internal/frei0reffect.h +++ b/effects/internal/frei0reffect.h @@ -23,32 +23,31 @@ #ifndef NOFREI0R -#include "project/effect.h" - #include -#include "io/crossplatformlib.h" +#include "effects/effect.h" +#include "global/crossplatformlib.h" typedef void (*f0rGetParamInfo)(f0r_param_info_t * info, - int param_index ); + int param_index ); class Frei0rEffect : public Effect { - Q_OBJECT + Q_OBJECT public: Frei0rEffect(Clip* c, const EffectMeta* em); - ~Frei0rEffect(); + ~Frei0rEffect(); - virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size); + virtual void process_image(double timecode, uint8_t* input, uint8_t* output, int size); - virtual void refresh(); + virtual void refresh(); private: - ModulePtr handle; - f0r_instance_t instance; - int param_count; - f0rGetParamInfo get_param_info; - void destruct_module(); - void construct_module(); - bool open; + ModulePtr handle; + f0r_instance_t instance; + int param_count; + f0rGetParamInfo get_param_info; + void destruct_module(); + void construct_module(); + bool open; }; #endif diff --git a/effects/internal/linearfadetransition.h b/effects/internal/linearfadetransition.h index f3716753a..bfb94c414 100644 --- a/effects/internal/linearfadetransition.h +++ b/effects/internal/linearfadetransition.h @@ -21,12 +21,12 @@ #ifndef LINEARFADETRANSITION_H #define LINEARFADETRANSITION_H -#include "project/transition.h" +#include "effects/transition.h" class LinearFadeTransition : public Transition { public: LinearFadeTransition(Clip* c, Clip* s, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); }; #endif // LINEARFADETRANSITION_H diff --git a/effects/internal/logarithmicfadetransition.h b/effects/internal/logarithmicfadetransition.h index a476351d1..e4b178881 100644 --- a/effects/internal/logarithmicfadetransition.h +++ b/effects/internal/logarithmicfadetransition.h @@ -21,12 +21,12 @@ #ifndef LOGARITHMICFADETRANSITION_H #define LOGARITHMICFADETRANSITION_H -#include "project/transition.h" +#include "effects/transition.h" class LogarithmicFadeTransition : public Transition { public: LogarithmicFadeTransition(Clip* c, Clip* s, const EffectMeta* em); - void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); + void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count); }; #endif // LOGARITHMICFADETRANSITION_H diff --git a/effects/internal/paneffect.h b/effects/internal/paneffect.h index aab759b54..5e767e04e 100644 --- a/effects/internal/paneffect.h +++ b/effects/internal/paneffect.h @@ -21,7 +21,7 @@ #ifndef PANEFFECT_H #define PANEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class PanEffect : public Effect { Q_OBJECT diff --git a/effects/internal/shakeeffect.cpp b/effects/internal/shakeeffect.cpp index 4c1ea170f..6467e2bb5 100644 --- a/effects/internal/shakeeffect.cpp +++ b/effects/internal/shakeeffect.cpp @@ -27,11 +27,10 @@ #include "ui/labelslider.h" #include "ui/collapsiblewidget.h" -#include "project/clip.h" -#include "project/sequence.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" #include "panels/timeline.h" - -#include "debug.h" +#include "global/debug.h" ShakeEffect::ShakeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { SetFlags(Effect::CoordsFlag); diff --git a/effects/internal/shakeeffect.h b/effects/internal/shakeeffect.h index 05c96022f..b199f493b 100644 --- a/effects/internal/shakeeffect.h +++ b/effects/internal/shakeeffect.h @@ -21,7 +21,7 @@ #ifndef SHAKEEFFECT_H #define SHAKEEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" #define RANDOM_VAL_SIZE 30 diff --git a/effects/internal/solideffect.cpp b/effects/internal/solideffect.cpp index 76e067f27..95b01cb2d 100644 --- a/effects/internal/solideffect.cpp +++ b/effects/internal/solideffect.cpp @@ -27,8 +27,8 @@ #include #include -#include "project/clip.h" -#include "project/sequence.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" const int SMPTE_BARS = 7; const int SMPTE_STRIP_COUNT = 3; diff --git a/effects/internal/solideffect.h b/effects/internal/solideffect.h index 0b5b22846..3d099b17f 100644 --- a/effects/internal/solideffect.h +++ b/effects/internal/solideffect.h @@ -21,7 +21,7 @@ #ifndef SOLIDEFFECT_H #define SOLIDEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" #include diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index 59b80b929..4c51f47e4 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -35,12 +35,12 @@ #include "ui/labelslider.h" #include "ui/collapsiblewidget.h" -#include "project/clip.h" -#include "project/sequence.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" #include "ui/comboboxex.h" #include "ui/colorbutton.h" #include "ui/fontcombobox.h" -#include "io/config.h" +#include "global/config.h" TextEffect::TextEffect(Clip* c, const EffectMeta* em) : Effect(c, em) diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h index e389a5873..b74356dbf 100644 --- a/effects/internal/texteffect.h +++ b/effects/internal/texteffect.h @@ -21,7 +21,7 @@ #ifndef TEXTEFFECT_H #define TEXTEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" #include #include diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index b10b9d916..6b37a6795 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -35,13 +35,13 @@ #include "ui/labelslider.h" #include "ui/collapsiblewidget.h" -#include "project/clip.h" -#include "project/sequence.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" #include "panels/viewer.h" #include "ui/comboboxex.h" #include "ui/colorbutton.h" #include "ui/fontcombobox.h" -#include "io/config.h" +#include "global/config.h" TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : Effect(c, em) diff --git a/effects/internal/timecodeeffect.h b/effects/internal/timecodeeffect.h index 1e8ba5ec8..2f48d9bc7 100644 --- a/effects/internal/timecodeeffect.h +++ b/effects/internal/timecodeeffect.h @@ -21,7 +21,7 @@ #ifndef TIMECODEEFFECT_H #define TIMECODEEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" #include #include diff --git a/effects/internal/toneeffect.cpp b/effects/internal/toneeffect.cpp index 95c33504d..a1758f86e 100644 --- a/effects/internal/toneeffect.cpp +++ b/effects/internal/toneeffect.cpp @@ -24,9 +24,8 @@ #define TONE_TYPE_SINE 0 -#include "project/clip.h" -#include "project/sequence.h" -#include "debug.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" ToneEffect::ToneEffect(Clip* c, const EffectMeta *em) : Effect(c, em), sinX(INT_MIN) { EffectRow* type_row = new EffectRow(this, tr("Type")); diff --git a/effects/internal/toneeffect.h b/effects/internal/toneeffect.h index 2b0223e47..a14f49a98 100644 --- a/effects/internal/toneeffect.h +++ b/effects/internal/toneeffect.h @@ -21,7 +21,7 @@ #ifndef TONEEFFECT_H #define TONEEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class ToneEffect : public Effect { Q_OBJECT diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 82103cfe9..03c219dcd 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -30,14 +30,14 @@ #include #include "ui/collapsiblewidget.h" -#include "project/clip.h" -#include "project/sequence.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" #include "project/footage.h" -#include "io/math.h" +#include "global/math.h" #include "ui/labelslider.h" #include "ui/comboboxex.h" #include "panels/project.h" -#include "debug.h" +#include "global/debug.h" #include "panels/panels.h" #include "panels/viewer.h" diff --git a/effects/internal/transformeffect.h b/effects/internal/transformeffect.h index 13b007bc0..84f64fadb 100644 --- a/effects/internal/transformeffect.h +++ b/effects/internal/transformeffect.h @@ -21,7 +21,7 @@ #ifndef TRANSFORMEFFECT_H #define TRANSFORMEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class TransformEffect : public Effect { Q_OBJECT diff --git a/effects/internal/voideffect.cpp b/effects/internal/voideffect.cpp index d68f2ddbe..bf3192cd6 100644 --- a/effects/internal/voideffect.cpp +++ b/effects/internal/voideffect.cpp @@ -25,7 +25,7 @@ #include #include "ui/collapsiblewidget.h" -#include "debug.h" +#include "global/debug.h" VoidEffect::VoidEffect(Clip* c, const QString& n) : Effect(c, nullptr) { QString display_name; diff --git a/effects/internal/voideffect.h b/effects/internal/voideffect.h index 7d524302f..a0c49c7ba 100644 --- a/effects/internal/voideffect.h +++ b/effects/internal/voideffect.h @@ -27,7 +27,7 @@ * isn't lost if the user saves over the project. */ -#include "project/effect.h" +#include "effects/effect.h" class VoidEffect : public Effect { Q_OBJECT diff --git a/effects/internal/volumeeffect.cpp b/effects/internal/volumeeffect.cpp index 1b12216f5..e01d5241c 100644 --- a/effects/internal/volumeeffect.cpp +++ b/effects/internal/volumeeffect.cpp @@ -34,7 +34,7 @@ VolumeEffect::VolumeEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { // set defaults volume_val->SetDefault(1); - volume_val->SetDisplayType(LabelSlider::LABELSLIDER_DECIBEL); + volume_val->SetDisplayType(LabelSlider::Decibel); } void VolumeEffect::process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int) { diff --git a/effects/internal/volumeeffect.h b/effects/internal/volumeeffect.h index 584c6c00c..80e0adc70 100644 --- a/effects/internal/volumeeffect.h +++ b/effects/internal/volumeeffect.h @@ -21,7 +21,7 @@ #ifndef VOLUMEEFFECT_H #define VOLUMEEFFECT_H -#include "project/effect.h" +#include "effects/effect.h" class VolumeEffect : public Effect { Q_OBJECT diff --git a/effects/internal/vsthost.cpp b/effects/internal/vsthost.cpp index f831abc4e..ade778f06 100644 --- a/effects/internal/vsthost.cpp +++ b/effects/internal/vsthost.cpp @@ -32,8 +32,8 @@ #include #include "rendering/audio.h" -#include "mainwindow.h" -#include "debug.h" +#include "ui/mainwindow.h" +#include "global/debug.h" #ifdef __linux__ #include diff --git a/effects/internal/vsthost.h b/effects/internal/vsthost.h index 5e30312ba..5dc06a0cf 100644 --- a/effects/internal/vsthost.h +++ b/effects/internal/vsthost.h @@ -23,9 +23,9 @@ #ifndef NOVST -#include "project/effect.h" +#include "effects/effect.h" -#include "io/crossplatformlib.h" +#include "global/crossplatformlib.h" #include "include/vestige.h" diff --git a/project/keyframe.cpp b/effects/keyframe.cpp similarity index 93% rename from project/keyframe.cpp rename to effects/keyframe.cpp index 64a36ce2d..c7518477b 100644 --- a/project/keyframe.cpp +++ b/effects/keyframe.cpp @@ -23,10 +23,11 @@ #include #include "effectfields.h" -#include "undo.h" +#include "undo/undo.h" #include "panels/panels.h" -EffectKeyframe::EffectKeyframe() { +EffectKeyframe::EffectKeyframe() +{ pre_handle_x = -40; pre_handle_y = 0; post_handle_x = 40; diff --git a/project/keyframe.h b/effects/keyframe.h similarity index 81% rename from project/keyframe.h rename to effects/keyframe.h index 9602a670e..241d28ef8 100644 --- a/project/keyframe.h +++ b/effects/keyframe.h @@ -27,17 +27,17 @@ class EffectField; class EffectKeyframe { public: - EffectKeyframe(); + EffectKeyframe(); - long time; - int type; - QVariant data; + int type; + long time; + QVariant data; - // only for bezier type - double pre_handle_x; - double pre_handle_y; - double post_handle_x; - double post_handle_y; + // only for bezier type + double pre_handle_x; + double pre_handle_y; + double post_handle_x; + double post_handle_y; }; void delete_keyframes(QVector &selected_key_fields, QVector &selected_keys); diff --git a/effects/boxblur.frag b/effects/shaders/boxblur.frag similarity index 100% rename from effects/boxblur.frag rename to effects/shaders/boxblur.frag diff --git a/effects/boxblur.xml b/effects/shaders/boxblur.xml similarity index 100% rename from effects/boxblur.xml rename to effects/shaders/boxblur.xml diff --git a/effects/bulge.frag b/effects/shaders/bulge.frag similarity index 100% rename from effects/bulge.frag rename to effects/shaders/bulge.frag diff --git a/effects/bulge.xml b/effects/shaders/bulge.xml similarity index 100% rename from effects/bulge.xml rename to effects/shaders/bulge.xml diff --git a/effects/chromakey.frag b/effects/shaders/chromakey.frag similarity index 100% rename from effects/chromakey.frag rename to effects/shaders/chromakey.frag diff --git a/effects/chromakey.xml b/effects/shaders/chromakey.xml similarity index 100% rename from effects/chromakey.xml rename to effects/shaders/chromakey.xml diff --git a/effects/chromaticaberration.frag b/effects/shaders/chromaticaberration.frag similarity index 100% rename from effects/chromaticaberration.frag rename to effects/shaders/chromaticaberration.frag diff --git a/effects/chromaticaberration.xml b/effects/shaders/chromaticaberration.xml similarity index 100% rename from effects/chromaticaberration.xml rename to effects/shaders/chromaticaberration.xml diff --git a/effects/colorcorrection.frag b/effects/shaders/colorcorrection.frag similarity index 100% rename from effects/colorcorrection.frag rename to effects/shaders/colorcorrection.frag diff --git a/effects/colorcorrection.xml b/effects/shaders/colorcorrection.xml similarity index 100% rename from effects/colorcorrection.xml rename to effects/shaders/colorcorrection.xml diff --git a/effects/colorsel.frag b/effects/shaders/colorsel.frag similarity index 100% rename from effects/colorsel.frag rename to effects/shaders/colorsel.frag diff --git a/effects/colorsel.xml b/effects/shaders/colorsel.xml similarity index 100% rename from effects/colorsel.xml rename to effects/shaders/colorsel.xml diff --git a/effects/common.frag b/effects/shaders/common.frag similarity index 100% rename from effects/common.frag rename to effects/shaders/common.frag diff --git a/effects/common.vert b/effects/shaders/common.vert similarity index 100% rename from effects/common.vert rename to effects/shaders/common.vert diff --git a/effects/crop.frag b/effects/shaders/crop.frag similarity index 100% rename from effects/crop.frag rename to effects/shaders/crop.frag diff --git a/effects/crop.xml b/effects/shaders/crop.xml similarity index 100% rename from effects/crop.xml rename to effects/shaders/crop.xml diff --git a/effects/crossstitch.frag b/effects/shaders/crossstitch.frag similarity index 100% rename from effects/crossstitch.frag rename to effects/shaders/crossstitch.frag diff --git a/effects/crossstitch.xml b/effects/shaders/crossstitch.xml similarity index 100% rename from effects/crossstitch.xml rename to effects/shaders/crossstitch.xml diff --git a/effects/directionalblur.frag b/effects/shaders/directionalblur.frag similarity index 100% rename from effects/directionalblur.frag rename to effects/shaders/directionalblur.frag diff --git a/effects/directionalblur.xml b/effects/shaders/directionalblur.xml similarity index 100% rename from effects/directionalblur.xml rename to effects/shaders/directionalblur.xml diff --git a/effects/dropshadow.xml.disabled b/effects/shaders/dropshadow.xml.disabled similarity index 100% rename from effects/dropshadow.xml.disabled rename to effects/shaders/dropshadow.xml.disabled diff --git a/effects/emboss.frag b/effects/shaders/emboss.frag similarity index 100% rename from effects/emboss.frag rename to effects/shaders/emboss.frag diff --git a/effects/emboss.xml b/effects/shaders/emboss.xml similarity index 100% rename from effects/emboss.xml rename to effects/shaders/emboss.xml diff --git a/effects/findedges.frag b/effects/shaders/findedges.frag similarity index 100% rename from effects/findedges.frag rename to effects/shaders/findedges.frag diff --git a/effects/findedges.xml.disabled b/effects/shaders/findedges.xml.disabled similarity index 100% rename from effects/findedges.xml.disabled rename to effects/shaders/findedges.xml.disabled diff --git a/effects/fisheye.frag b/effects/shaders/fisheye.frag similarity index 100% rename from effects/fisheye.frag rename to effects/shaders/fisheye.frag diff --git a/effects/fisheye.xml b/effects/shaders/fisheye.xml similarity index 100% rename from effects/fisheye.xml rename to effects/shaders/fisheye.xml diff --git a/effects/flip.frag b/effects/shaders/flip.frag similarity index 100% rename from effects/flip.frag rename to effects/shaders/flip.frag diff --git a/effects/flip.xml b/effects/shaders/flip.xml similarity index 100% rename from effects/flip.xml rename to effects/shaders/flip.xml diff --git a/effects/gaussianblur.frag b/effects/shaders/gaussianblur.frag similarity index 100% rename from effects/gaussianblur.frag rename to effects/shaders/gaussianblur.frag diff --git a/effects/gaussianblur.xml b/effects/shaders/gaussianblur.xml similarity index 100% rename from effects/gaussianblur.xml rename to effects/shaders/gaussianblur.xml diff --git a/effects/huesatbri.frag b/effects/shaders/huesatbri.frag similarity index 100% rename from effects/huesatbri.frag rename to effects/shaders/huesatbri.frag diff --git a/effects/huesatbri.xml b/effects/shaders/huesatbri.xml similarity index 100% rename from effects/huesatbri.xml rename to effects/shaders/huesatbri.xml diff --git a/effects/invert.frag b/effects/shaders/invert.frag similarity index 100% rename from effects/invert.frag rename to effects/shaders/invert.frag diff --git a/effects/invert.xml b/effects/shaders/invert.xml similarity index 100% rename from effects/invert.xml rename to effects/shaders/invert.xml diff --git a/effects/lumakey.frag b/effects/shaders/lumakey.frag similarity index 100% rename from effects/lumakey.frag rename to effects/shaders/lumakey.frag diff --git a/effects/lumakey.xml b/effects/shaders/lumakey.xml similarity index 100% rename from effects/lumakey.xml rename to effects/shaders/lumakey.xml diff --git a/effects/noise.frag b/effects/shaders/noise.frag similarity index 100% rename from effects/noise.frag rename to effects/shaders/noise.frag diff --git a/effects/noise.xml b/effects/shaders/noise.xml similarity index 100% rename from effects/noise.xml rename to effects/shaders/noise.xml diff --git a/effects/pixelate.frag b/effects/shaders/pixelate.frag similarity index 100% rename from effects/pixelate.frag rename to effects/shaders/pixelate.frag diff --git a/effects/pixelate.xml b/effects/shaders/pixelate.xml similarity index 100% rename from effects/pixelate.xml rename to effects/shaders/pixelate.xml diff --git a/effects/posterize.frag b/effects/shaders/posterize.frag similarity index 100% rename from effects/posterize.frag rename to effects/shaders/posterize.frag diff --git a/effects/posterize.xml b/effects/shaders/posterize.xml similarity index 100% rename from effects/posterize.xml rename to effects/shaders/posterize.xml diff --git a/effects/radialblur.frag b/effects/shaders/radialblur.frag similarity index 100% rename from effects/radialblur.frag rename to effects/shaders/radialblur.frag diff --git a/effects/radialblur.xml b/effects/shaders/radialblur.xml similarity index 100% rename from effects/radialblur.xml rename to effects/shaders/radialblur.xml diff --git a/effects/ripple.frag b/effects/shaders/ripple.frag similarity index 100% rename from effects/ripple.frag rename to effects/shaders/ripple.frag diff --git a/effects/ripple.xml b/effects/shaders/ripple.xml similarity index 100% rename from effects/ripple.xml rename to effects/shaders/ripple.xml diff --git a/effects/sphere.frag b/effects/shaders/sphere.frag similarity index 100% rename from effects/sphere.frag rename to effects/shaders/sphere.frag diff --git a/effects/sphere.xml b/effects/shaders/sphere.xml similarity index 100% rename from effects/sphere.xml rename to effects/shaders/sphere.xml diff --git a/effects/swirl.frag b/effects/shaders/swirl.frag similarity index 100% rename from effects/swirl.frag rename to effects/shaders/swirl.frag diff --git a/effects/swirl.xml b/effects/shaders/swirl.xml similarity index 100% rename from effects/swirl.xml rename to effects/shaders/swirl.xml diff --git a/effects/tile.frag b/effects/shaders/tile.frag similarity index 100% rename from effects/tile.frag rename to effects/shaders/tile.frag diff --git a/effects/tile.xml b/effects/shaders/tile.xml similarity index 100% rename from effects/tile.xml rename to effects/shaders/tile.xml diff --git a/effects/toonify.frag b/effects/shaders/toonify.frag similarity index 100% rename from effects/toonify.frag rename to effects/shaders/toonify.frag diff --git a/effects/toonify.xml b/effects/shaders/toonify.xml similarity index 100% rename from effects/toonify.xml rename to effects/shaders/toonify.xml diff --git a/effects/vignette.frag b/effects/shaders/vignette.frag similarity index 100% rename from effects/vignette.frag rename to effects/shaders/vignette.frag diff --git a/effects/vignette.xml b/effects/shaders/vignette.xml similarity index 100% rename from effects/vignette.xml rename to effects/shaders/vignette.xml diff --git a/effects/volumetriclight.frag b/effects/shaders/volumetriclight.frag similarity index 100% rename from effects/volumetriclight.frag rename to effects/shaders/volumetriclight.frag diff --git a/effects/volumetriclight.xml b/effects/shaders/volumetriclight.xml similarity index 100% rename from effects/volumetriclight.xml rename to effects/shaders/volumetriclight.xml diff --git a/effects/wave.frag b/effects/shaders/wave.frag similarity index 100% rename from effects/wave.frag rename to effects/shaders/wave.frag diff --git a/effects/wave.xml b/effects/shaders/wave.xml similarity index 100% rename from effects/wave.xml rename to effects/shaders/wave.xml diff --git a/project/transition.cpp b/effects/transition.cpp similarity index 92% rename from project/transition.cpp rename to effects/transition.cpp index aaf1b811c..1378823c3 100644 --- a/project/transition.cpp +++ b/effects/transition.cpp @@ -20,12 +20,12 @@ #include "transition.h" -#include "mainwindow.h" -#include "clip.h" -#include "sequence.h" -#include "debug.h" +#include "ui/mainwindow.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" +#include "global/debug.h" -#include "io/clipboard.h" +#include "project/clipboard.h" #include "effects/internal/crossdissolvetransition.h" #include "effects/internal/linearfadetransition.h" @@ -49,7 +49,7 @@ Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : length_field = new DoubleField(length_row, "length"); length_field->SetDefault(30); length_field->SetMinimum(0); - length_field->SetDisplayType(LabelSlider::LABELSLIDER_FRAMENUMBER); + length_field->SetDisplayType(LabelSlider::FrameNumber); length_field->SetFrameRate(parent_clip->sequence == nullptr ? parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider())); diff --git a/project/transition.h b/effects/transition.h similarity index 100% rename from project/transition.h rename to effects/transition.h diff --git a/io/config.cpp b/global/config.cpp similarity index 100% rename from io/config.cpp rename to global/config.cpp diff --git a/io/config.h b/global/config.h similarity index 100% rename from io/config.h rename to global/config.h diff --git a/io/crossplatformlib.cpp b/global/crossplatformlib.cpp similarity index 100% rename from io/crossplatformlib.cpp rename to global/crossplatformlib.cpp diff --git a/io/crossplatformlib.h b/global/crossplatformlib.h similarity index 100% rename from io/crossplatformlib.h rename to global/crossplatformlib.h diff --git a/debug.cpp b/global/debug.cpp similarity index 100% rename from debug.cpp rename to global/debug.cpp diff --git a/debug.h b/global/debug.h similarity index 100% rename from debug.h rename to global/debug.h diff --git a/oliveglobal.cpp b/global/global.cpp similarity index 95% rename from oliveglobal.cpp rename to global/global.cpp index 07dd08970..9df7c5143 100644 --- a/oliveglobal.cpp +++ b/global/global.cpp @@ -18,16 +18,14 @@ ***/ -#include "oliveglobal.h" +#include "global/global.h" -#include "mainwindow.h" #include "panels/panels.h" -#include "io/path.h" -#include "io/config.h" +#include "global/path.h" +#include "global/config.h" -#include "ui/mediaiconservice.h" #include "rendering/audio.h" @@ -39,8 +37,10 @@ #include "dialogs/speeddialog.h" #include "dialogs/actionsearch.h" -#include "project/sequence.h" +#include "timeline/sequence.h" +#include "ui/mediaiconservice.h" +#include "ui/mainwindow.h" #include "ui/updatenotification.h" #include diff --git a/oliveglobal.h b/global/global.h similarity index 96% rename from oliveglobal.h rename to global/global.h index 305beefb8..429960a11 100644 --- a/oliveglobal.h +++ b/global/global.h @@ -22,7 +22,7 @@ #define OLIVEGLOBAL_H #include -#include "project/undo.h" +#include "undo/undo.h" #include #include diff --git a/io/math.cpp b/global/math.cpp similarity index 100% rename from io/math.cpp rename to global/math.cpp diff --git a/io/math.h b/global/math.h similarity index 100% rename from io/math.h rename to global/math.h diff --git a/io/path.cpp b/global/path.cpp similarity index 100% rename from io/path.cpp rename to global/path.cpp diff --git a/io/path.h b/global/path.h similarity index 100% rename from io/path.h rename to global/path.h diff --git a/io/qpainterwrapper.cpp b/io/qpainterwrapper.cpp deleted file mode 100644 index 9d37e7641..000000000 --- a/io/qpainterwrapper.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "qpainterwrapper.h" - -#include -#include "debug.h" - -// exposes several QPainter functions to QJSEngine - -QPainterWrapper painter_wrapper; - -QPainterWrapper::QPainterWrapper() {} - -QColor get_color_from_string(const QString& s) { - // workaround for alpha - if (s.at(0) == '#' && s.length() == 9) { - QColor color(s.left(7)); - color.setAlpha(s.mid(7).toInt(nullptr, 16)); - return color; - } else { - return QColor(s); - } -} - -void QPainterWrapper::fill(const QString& c) { - img->fill(get_color_from_string(c)); -} - -void QPainterWrapper::fillRect(int x, int y, int width, int height, const QString& brush) { - painter->fillRect(x, y, width, height, get_color_from_string(brush)); -} - -void QPainterWrapper::drawRect(int x, int y, int width, int height) { - painter->drawRect(x, y, width, height); -} - -void QPainterWrapper::setPen(const QString& pen) { - painter->setPen(get_color_from_string(pen)); -} - -void QPainterWrapper::setBrush(const QString& brush) { - painter->setBrush(get_color_from_string(brush)); -} diff --git a/io/qpainterwrapper.h b/io/qpainterwrapper.h deleted file mode 100644 index 1f217ef95..000000000 --- a/io/qpainterwrapper.h +++ /dev/null @@ -1,44 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#ifndef QPAINTERWRAPPER_H -#define QPAINTERWRAPPER_H - -#include - -class QPainter; - -class QPainterWrapper : public QObject { - Q_OBJECT -public: - QPainterWrapper(); - QImage* img; - QPainter* painter; -public slots: - void fill(const QString& color); - void fillRect(int x, int y, int width, int height, const QString& brush); - void drawRect(int x, int y, int width, int height); - void setPen(const QString& pen); - void setBrush(const QString& brush); -}; - -extern QPainterWrapper painter_wrapper; - -#endif // QPAINTERWRAPPER_H diff --git a/main.cpp b/main.cpp index 69f99ee5e..ed250177e 100644 --- a/main.cpp +++ b/main.cpp @@ -18,23 +18,21 @@ ***/ -#include "mainwindow.h" #include -#include "debug.h" - -#include "oliveglobal.h" -#include "ui/mediaiconservice.h" +#include "global/debug.h" +#include "global/config.h" +#include "global/global.h" #include "panels/timeline.h" - -#include "io/config.h" +#include "ui/mediaiconservice.h" +#include "ui/mainwindow.h" extern "C" { #include #include } -int main(int argc, char *argv[]) { +int main(int argc, char *argv[]) { olive::Global = std::unique_ptr(new OliveGlobal); bool launch_fullscreen = false; diff --git a/olive.pro b/olive.pro index baa966ea2..252f51051 100644 --- a/olive.pro +++ b/olive.pro @@ -54,7 +54,7 @@ CONFIG(debug, debug|release) { SOURCES += \ main.cpp \ - mainwindow.cpp \ + ui/mainwindow.cpp \ panels/project.cpp \ panels/effectcontrols.cpp \ panels/viewer.cpp \ @@ -64,22 +64,22 @@ SOURCES += \ ui/timelinewidget.cpp \ project/media.cpp \ project/footage.cpp \ - project/sequence.cpp \ - project/clip.cpp \ - io/config.cpp \ + timeline/sequence.cpp \ + timeline/clip.cpp \ + global/config.cpp \ dialogs/newsequencedialog.cpp \ ui/viewerwidget.cpp \ ui/viewercontainer.cpp \ dialogs/exportdialog.cpp \ ui/collapsiblewidget.cpp \ panels/panels.cpp \ - io/exportthread.cpp \ + rendering/exportthread.cpp \ ui/timelineheader.cpp \ - io/previewgenerator.cpp \ + project/previewgenerator.cpp \ ui/labelslider.cpp \ dialogs/preferencesdialog.cpp \ ui/audiomonitor.cpp \ - project/undo.cpp \ + undo/undo.cpp \ ui/scrollarea.cpp \ ui/comboboxex.cpp \ ui/colorbutton.cpp \ @@ -89,14 +89,14 @@ SOURCES += \ ui/keyframeview.cpp \ ui/texteditex.cpp \ dialogs/demonotice.cpp \ - project/marker.cpp \ + timeline/marker.cpp \ dialogs/speeddialog.cpp \ dialogs/mediapropertiesdialog.cpp \ project/projectmodel.cpp \ - io/loadthread.cpp \ + project/loadthread.cpp \ dialogs/loaddialog.cpp \ - debug.cpp \ - io/path.cpp \ + global/debug.cpp \ + global/path.cpp \ effects/internal/linearfadetransition.cpp \ effects/internal/transformeffect.cpp \ effects/internal/solideffect.cpp \ @@ -111,13 +111,11 @@ SOURCES += \ effects/internal/exponentialfadetransition.cpp \ effects/internal/logarithmicfadetransition.cpp \ effects/internal/cornerpineffect.cpp \ - io/math.cpp \ - io/qpainterwrapper.cpp \ - project/effect.cpp \ - project/transition.cpp \ - project/effectrow.cpp \ - project/effectgizmo.cpp \ - io/clipboard.cpp \ + global/math.cpp \ + effects/effect.cpp \ + effects/effectrow.cpp \ + effects/effectgizmo.cpp \ + project/clipboard.cpp \ ui/resizablescrollbar.cpp \ ui/sourceiconview.cpp \ project/sourcescommon.cpp \ @@ -126,7 +124,7 @@ SOURCES += \ ui/graphview.cpp \ ui/keyframedrawing.cpp \ ui/clickablelabel.cpp \ - project/keyframe.cpp \ + effects/keyframe.cpp \ ui/rectangleselect.cpp \ dialogs/actionsearch.cpp \ ui/embeddedfilechooser.cpp \ @@ -137,18 +135,18 @@ SOURCES += \ ui/viewerwindow.cpp \ project/projectfilter.cpp \ effects/internal/frei0reffect.cpp \ - project/effectloaders.cpp \ - io/crossplatformlib.cpp \ + effects/effectloaders.cpp \ + global/crossplatformlib.cpp \ effects/internal/vsthost.cpp \ ui/flowlayout.cpp \ dialogs/proxydialog.cpp \ - io/proxygenerator.cpp \ + project/proxygenerator.cpp \ dialogs/advancedvideodialog.cpp \ ui/cursors.cpp \ ui/menuhelper.cpp \ - oliveglobal.cpp \ + global/global.cpp \ ui/focusfilter.cpp \ - project/comboaction.cpp \ + undo/comboaction.cpp \ ui/mediaiconservice.cpp \ ui/panel.cpp \ effects/internal/dropshadoweffect.cpp \ @@ -161,20 +159,21 @@ SOURCES += \ rendering/framebufferobject.cpp \ ui/updatenotification.cpp \ ui/icons.cpp \ - project/effectfields/doublefield.cpp \ - project/effectfields/fontfield.cpp \ - project/effectfields/effectfield.cpp \ - project/effectfields/colorfield.cpp \ - project/effectfields/stringfield.cpp \ - project/effectfields/boolfield.cpp \ - project/effectfields/combofield.cpp \ - project/effectfields/filefield.cpp \ - project/effectfields/labelfield.cpp \ - project/effectfields/buttonfield.cpp \ - ui/effectui.cpp + effects/fields/doublefield.cpp \ + effects/fields/fontfield.cpp \ + effects/effectfield.cpp \ + effects/fields/colorfield.cpp \ + effects/fields/stringfield.cpp \ + effects/fields/boolfield.cpp \ + effects/fields/combofield.cpp \ + effects/fields/filefield.cpp \ + effects/fields/labelfield.cpp \ + effects/fields/buttonfield.cpp \ + ui/effectui.cpp \ + effects/transition.cpp HEADERS += \ - mainwindow.h \ + ui/mainwindow.h \ panels/project.h \ panels/effectcontrols.h \ panels/viewer.h \ @@ -184,23 +183,23 @@ HEADERS += \ ui/timelinewidget.h \ project/media.h \ project/footage.h \ - project/sequence.h \ - project/clip.h \ - io/config.h \ + timeline/sequence.h \ + timeline/clip.h \ + global/config.h \ dialogs/newsequencedialog.h \ ui/viewerwidget.h \ ui/viewercontainer.h \ dialogs/exportdialog.h \ ui/collapsiblewidget.h \ panels/panels.h \ - io/exportthread.h \ + rendering/exportthread.h \ ui/timelinetools.h \ ui/timelineheader.h \ - io/previewgenerator.h \ + project/previewgenerator.h \ ui/labelslider.h \ dialogs/preferencesdialog.h \ ui/audiomonitor.h \ - project/undo.h \ + undo/undo.h \ ui/scrollarea.h \ ui/comboboxex.h \ ui/colorbutton.h \ @@ -210,15 +209,15 @@ HEADERS += \ ui/keyframeview.h \ ui/texteditex.h \ dialogs/demonotice.h \ - project/marker.h \ - project/selection.h \ + timeline/marker.h \ + timeline/selection.h \ dialogs/speeddialog.h \ dialogs/mediapropertiesdialog.h \ project/projectmodel.h \ - io/loadthread.h \ + project/loadthread.h \ dialogs/loaddialog.h \ - debug.h \ - io/path.h \ + global/debug.h \ + global/path.h \ effects/internal/transformeffect.h \ effects/internal/solideffect.h \ effects/internal/texteffect.h \ @@ -233,14 +232,12 @@ HEADERS += \ effects/internal/exponentialfadetransition.h \ effects/internal/logarithmicfadetransition.h \ effects/internal/cornerpineffect.h \ - io/math.h \ - io/qpainterwrapper.h \ - project/effect.h \ - project/transition.h \ - project/effectrow.h \ + global/math.h \ + effects/effect.h \ + effects/effectrow.h \ effects/internal/cubetransition.h \ - project/effectgizmo.h \ - io/clipboard.h \ + effects/effectgizmo.h \ + project/clipboard.h \ ui/resizablescrollbar.h \ ui/sourceiconview.h \ project/sourcescommon.h \ @@ -249,7 +246,7 @@ HEADERS += \ ui/graphview.h \ ui/keyframedrawing.h \ ui/clickablelabel.h \ - project/keyframe.h \ + effects/keyframe.h \ ui/rectangleselect.h \ dialogs/actionsearch.h \ ui/embeddedfilechooser.h \ @@ -260,19 +257,19 @@ HEADERS += \ ui/viewerwindow.h \ project/projectfilter.h \ effects/internal/frei0reffect.h \ - project/effectloaders.h \ - io/crossplatformlib.h \ + effects/effectloaders.h \ + global/crossplatformlib.h \ effects/internal/vsthost.h \ ui/flowlayout.h \ dialogs/proxydialog.h \ - io/proxygenerator.h \ + project/proxygenerator.h \ dialogs/advancedvideodialog.h \ ui/cursors.h \ ui/menuhelper.h \ - oliveglobal.h \ + global/global.h \ project/projectelements.h \ ui/focusfilter.h \ - project/comboaction.h \ + undo/comboaction.h \ ui/mediaiconservice.h \ ui/panel.h \ effects/internal/dropshadoweffect.h \ @@ -285,18 +282,19 @@ HEADERS += \ rendering/framebufferobject.h \ ui/updatenotification.h \ ui/icons.h \ - project/effectfields/doublefield.h \ - project/effectfields/fontfield.h \ - project/effectfields/effectfield.h \ - project/effectfields.h \ - project/effectfields/colorfield.h \ - project/effectfields/stringfield.h \ - project/effectfields/boolfield.h \ - project/effectfields/combofield.h \ - project/effectfields/filefield.h \ - project/effectfields/labelfield.h \ - project/effectfields/buttonfield.h \ - ui/effectui.h + effects/fields/doublefield.h \ + effects/fields/fontfield.h \ + effects/effectfield.h \ + effects/effectfields.h \ + effects/fields/stringfield.h \ + effects/fields/filefield.h \ + effects/fields/labelfield.h \ + ui/effectui.h \ + effects/fields/boolfield.h \ + effects/fields/buttonfield.h \ + effects/fields/colorfield.h \ + effects/fields/combofield.h \ + effects/transition.h FORMS += diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 4feaa3e05..326016598 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -33,24 +33,24 @@ #include #include "panels/panels.h" -#include "project/effect.h" -#include "project/clip.h" -#include "project/transition.h" +#include "effects/effect.h" +#include "effects/transition.h" +#include "timeline/clip.h" #include "ui/collapsiblewidget.h" -#include "project/sequence.h" -#include "project/undo.h" +#include "timeline/sequence.h" +#include "undo/undo.h" #include "panels/project.h" #include "panels/timeline.h" #include "panels/viewer.h" #include "panels/grapheditor.h" #include "ui/viewerwidget.h" #include "ui/menuhelper.h" -#include "io/clipboard.h" -#include "io/config.h" +#include "project/clipboard.h" +#include "global/config.h" #include "ui/timelineheader.h" #include "ui/keyframeview.h" #include "ui/resizablescrollbar.h" -#include "debug.h" +#include "global/debug.h" EffectControls::EffectControls(QWidget *parent) : Panel(parent), @@ -130,6 +130,22 @@ void EffectControls::menu_select(QAction* q) { } void EffectControls::update_keyframes() { + for (int i=0;iGetEffect(); + + for (int j=0;jrow_count();j++) { + + EffectRow* row = effect->row(j); + + for (int k=0;kFieldCount();k++) { + EffectField* field = row->Field(k); + + field->UpdateWidgetValue(ui->Widget(j, k), field->Now()); + } + } + } + headers->update_zoom(zoom); keyframeView->update(); } diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index cfe9d6723..6f720da10 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -30,13 +30,13 @@ #include "ui/timelinetools.h" #include "ui/labelslider.h" #include "ui/graphview.h" -#include "project/effect.h" -#include "project/effectfields.h" -#include "project/effectrow.h" -#include "project/clip.h" +#include "effects/effect.h" +#include "effects/effectfields.h" +#include "effects/effectrow.h" +#include "timeline/clip.h" #include "rendering/renderfunctions.h" #include "panels.h" -#include "debug.h" +#include "global/debug.h" GraphEditor::GraphEditor(QWidget* parent) : Panel(parent), row(nullptr) { resize(720, 480); @@ -144,10 +144,10 @@ void GraphEditor::update_panel() { for (int i=0;iFieldCount();i++) { EffectField* field = row->Field(i); if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { - slider_proxies.at(slider_index)->set_value( - row->Field(i)->GetValueAt(playhead_to_clip_seconds(field->GetParentRow()->GetParentEffect()->parent_clip, - olive::ActiveSequence->playhead)).toDouble(), - false + slider_proxies.at(slider_index)->SetValue( + row->Field(i)->GetValueAt( + playhead_to_clip_seconds(field->GetParentRow()->GetParentEffect()->parent_clip, + olive::ActiveSequence->playhead)).toDouble() ); slider_index++; } @@ -192,7 +192,7 @@ void GraphEditor::set_row(EffectRow *r) { value_layout->addWidget(slider_button); LabelSlider* slider = new LabelSlider(); - slider->set_color(get_curve_color(i, r->FieldCount()).name()); + slider->SetColor(get_curve_color(i, r->FieldCount()).name()); connect(slider, SIGNAL(valueChanged()), this, SLOT(passthrough_slider_value())); slider_proxies.append(slider); value_layout->addWidget(slider); @@ -250,7 +250,7 @@ void GraphEditor::set_key_button_enabled(bool e, int type) { void GraphEditor::passthrough_slider_value() { for (int i=0;iset_value(slider_proxies.at(i)->value(), true); + slider_proxy_sources.at(i)->SetValue(slider_proxies.at(i)->value()); } } } diff --git a/panels/grapheditor.h b/panels/grapheditor.h index 826c7bcac..0ba0f3136 100644 --- a/panels/grapheditor.h +++ b/panels/grapheditor.h @@ -30,7 +30,7 @@ #include "ui/timelineheader.h" #include "ui/labelslider.h" #include "ui/keyframenavigator.h" -#include "project/effectrow.h" +#include "effects/effectrow.h" class GraphEditor : public Panel { Q_OBJECT diff --git a/panels/panels.cpp b/panels/panels.cpp index cdd3691ef..6d8cb3ad5 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -20,13 +20,12 @@ #include "panels.h" -#include "project/sequence.h" -#include "project/clip.h" -#include "project/transition.h" -#include "io/config.h" - -#include "project/effectloaders.h" -#include "debug.h" +#include "timeline/sequence.h" +#include "timeline/clip.h" +#include "effects/transition.h" +#include "global/config.h" +#include "effects/effectloaders.h" +#include "global/debug.h" #include #include @@ -43,62 +42,6 @@ void update_effect_controls() { int mode = kTransitionNone; if (olive::ActiveSequence != nullptr) { - /* - for (int i=0;iclips.size();i++) { - Clip* clip = olive::ActiveSequence->clips.at(i).get(); - if (clip != nullptr) { - for (int j=0;jselections.size();j++) { - const Selection& s = olive::ActiveSequence->selections.at(j); - bool add = true; - if (clip->timeline_in() >= s.in && clip->timeline_out() <= s.out && clip->track() == s.track) { - mode = kTransitionNone; - } else if (selection_contains_transition(s, clip, kTransitionOpening)) { - mode = kTransitionOpening; - } else if (selection_contains_transition(s, clip, kTransitionClosing)) { - mode = kTransitionClosing; - } else { - add = false; - } - - if (add) { - if (clip->track() < 0 && vclip == -1) { - vclip = i; - } else if (clip->track() >= 0 && aclip == -1) { - aclip = i; - } else { - vclip = -2; - aclip = -2; - multiple = true; - multiple = true; - break; - } - } - } - } - } - - if (!multiple) { - // check if aclip is linked to vclip - if (vclip >= 0) selected_clips.append(vclip); - if (aclip >= 0) selected_clips.append(aclip); - if (vclip >= 0 && aclip >= 0) { - bool found = false; - ClipPtr vclip_ref = olive::ActiveSequence->clips.at(vclip); - for (int i=0;ilinked.size();i++) { - if (vclip_ref->linked.at(i) == aclip) { - found = true; - break; - } - } - if (!found) { - // only display multiple clips if they're linked - selected_clips.clear(); - multiple = true; - } - } - } - */ - selected_clips = olive::ActiveSequence->SelectedClips(); // TODO handle selecting transitions diff --git a/panels/project.cpp b/panels/project.cpp index 86fe5dbf6..a609c5147 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -20,21 +20,20 @@ #include "project.h" -#include "oliveglobal.h" - +#include "global/global.h" #include "panels.h" #include "rendering/renderfunctions.h" -#include "io/previewgenerator.h" -#include "project/undo.h" -#include "mainwindow.h" -#include "io/config.h" +#include "project/previewgenerator.h" +#include "undo/undo.h" +#include "ui/mainwindow.h" +#include "global/config.h" #include "rendering/cacher.h" #include "dialogs/replaceclipmediadialog.h" #include "panels/effectcontrols.h" #include "dialogs/newsequencedialog.h" #include "dialogs/mediapropertiesdialog.h" #include "dialogs/loaddialog.h" -#include "io/clipboard.h" +#include "project/clipboard.h" #include "ui/sourcetable.h" #include "ui/sourceiconview.h" #include "ui/icons.h" @@ -42,7 +41,7 @@ #include "ui/mediaiconservice.h" #include "project/sourcescommon.h" #include "project/projectfilter.h" -#include "debug.h" +#include "global/debug.h" #include #include diff --git a/panels/project.h b/panels/project.h index 6c12294e3..4ee1d779f 100644 --- a/panels/project.h +++ b/panels/project.h @@ -32,10 +32,10 @@ #include "project/projectmodel.h" #include "project/projectfilter.h" #include "project/projectelements.h" -#include "project/undo.h" #include "project/sourcescommon.h" #include "ui/panel.h" #include "ui/sourceiconview.h" +#include "undo/undo.h" #include "ui/sourcetable.h" diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 48db4b0df..06d41798b 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -20,26 +20,24 @@ #include "timeline.h" -#include "oliveglobal.h" - +#include "global/global.h" #include "panels/panels.h" #include "project/projectelements.h" - #include "ui/timelinewidget.h" #include "ui/icons.h" #include "ui/viewerwidget.h" #include "rendering/audio.h" #include "rendering/cacher.h" #include "rendering/renderfunctions.h" -#include "io/config.h" -#include "io/clipboard.h" +#include "global/config.h" +#include "project/clipboard.h" #include "ui/timelineheader.h" #include "ui/resizablescrollbar.h" #include "ui/audiomonitor.h" #include "ui/flowlayout.h" #include "ui/cursors.h" -#include "mainwindow.h" -#include "debug.h" +#include "ui/mainwindow.h" +#include "global/debug.h" #include #include diff --git a/panels/timeline.h b/panels/timeline.h index 198e23c46..028c8977f 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -27,9 +27,9 @@ #include "ui/timelinewidget.h" #include "ui/timelinetools.h" -#include "project/selection.h" -#include "project/clip.h" -#include "project/undo.h" +#include "timeline/selection.h" +#include "timeline/clip.h" +#include "undo/undo.h" #include "ui/timelineheader.h" #include "ui/resizablescrollbar.h" #include "ui/audiomonitor.h" diff --git a/panels/viewer.cpp b/panels/viewer.cpp index dce62dd18..67c1f2c35 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -24,13 +24,13 @@ #include "timeline.h" #include "panels/project.h" #include "panels/effectcontrols.h" -#include "project/sequence.h" -#include "project/clip.h" +#include "timeline/sequence.h" +#include "timeline/clip.h" #include "panels/panels.h" -#include "io/config.h" +#include "global/config.h" #include "project/footage.h" #include "project/media.h" -#include "project/undo.h" +#include "undo/undo.h" #include "ui/audiomonitor.h" #include "rendering/renderfunctions.h" #include "ui/viewercontainer.h" @@ -38,8 +38,8 @@ #include "ui/timelineheader.h" #include "ui/resizablescrollbar.h" #include "ui/icons.h" -#include "oliveglobal.h" -#include "debug.h" +#include "global/global.h" +#include "global/debug.h" #define FRAMES_IN_ONE_MINUTE 1798 // 1800 - 2 #define FRAMES_IN_TEN_MINUTES 17978 // (FRAMES_IN_ONE_MINUTE * 10) - 2 @@ -79,10 +79,10 @@ Viewer::Viewer(QWidget *parent) : set_media(nullptr); current_timecode_slider->setEnabled(false); - current_timecode_slider->set_minimum_value(0); - current_timecode_slider->set_default_value(qSNaN()); - current_timecode_slider->set_value(0, false); - current_timecode_slider->set_display_type(LabelSlider::LABELSLIDER_FRAMENUMBER); + current_timecode_slider->SetMinimum(0); + current_timecode_slider->SetDefault(qSNaN()); + current_timecode_slider->SetValue(0); + current_timecode_slider->SetDisplayType(LabelSlider::FrameNumber); connect(current_timecode_slider, SIGNAL(valueChanged(double)), this, SLOT(update_playhead())); recording_flasher.setInterval(500); @@ -479,7 +479,7 @@ bool Viewer::WaitingForPlayWake() } void Viewer::update_playhead_timecode(long p) { - current_timecode_slider->set_value(p, false); + current_timecode_slider->SetValue(p); } void Viewer::update_end_timecode() { @@ -884,7 +884,7 @@ void Viewer::set_sequence(bool main, SequencePtr s) { go_to_end_frame->setEnabled(!null_sequence); if (!null_sequence) { - current_timecode_slider->set_frame_rate(seq->frame_rate); + current_timecode_slider->SetFrameRate(seq->frame_rate); playback_updater.setInterval(qFloor(1000 / seq->frame_rate)); diff --git a/panels/viewer.h b/panels/viewer.h index 0f4ad5bb8..8376fee6d 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -26,7 +26,7 @@ #include #include -#include "project/marker.h" +#include "timeline/marker.h" #include "project/media.h" #include "ui/panel.h" diff --git a/io/clipboard.cpp b/project/clipboard.cpp similarity index 86% rename from io/clipboard.cpp rename to project/clipboard.cpp index cd5de7902..47a13385b 100644 --- a/io/clipboard.cpp +++ b/project/clipboard.cpp @@ -20,15 +20,15 @@ #include "clipboard.h" -#include "project/clip.h" -#include "project/effect.h" -#include "project/transition.h" +#include "timeline/clip.h" +#include "effects/effect.h" +#include "effects/transition.h" int clipboard_type = CLIPBOARD_TYPE_CLIP; QVector clipboard; QVector clipboard_transitions; void clear_clipboard() { - clipboard.clear(); - clipboard_transitions.clear(); + clipboard.clear(); + clipboard_transitions.clear(); } diff --git a/io/clipboard.h b/project/clipboard.h similarity index 97% rename from io/clipboard.h rename to project/clipboard.h index 5cb005d2b..4ca8c580d 100644 --- a/io/clipboard.h +++ b/project/clipboard.h @@ -23,7 +23,7 @@ #include -#include +#include #define CLIPBOARD_TYPE_CLIP 0 #define CLIPBOARD_TYPE_EFFECT 1 diff --git a/project/effectfields.h b/project/effectfields.h deleted file mode 100644 index c05a3d4df..000000000 --- a/project/effectfields.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef EFFECTFIELDS_H -#define EFFECTFIELDS_H - -#include "effectfields/boolfield.h" -#include "effectfields/buttonfield.h" -#include "effectfields/colorfield.h" -#include "effectfields/combofield.h" -#include "effectfields/doublefield.h" -#include "effectfields/filefield.h" -#include "effectfields/fontfield.h" -#include "effectfields/labelfield.h" -#include "effectfields/stringfield.h" - -#endif // EFFECTFIELDS_H diff --git a/project/effectloaders.cpp b/project/effectloaders.cpp deleted file mode 100644 index 443caec1e..000000000 --- a/project/effectloaders.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/*** - - Olive - Non-Linear Video Editor - Copyright (C) 2019 Olive Team - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -***/ - -#include "effectloaders.h" - -#include "project/effect.h" -#include "project/transition.h" -#include "io/path.h" -#include "panels/panels.h" -#include "panels/effectcontrols.h" -#include "io/crossplatformlib.h" -#include "io/config.h" - -#include -#include - -#include - -#ifndef NOFREI0R -#include -typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info); -#endif - -void load_internal_effects() { - if (!olive::CurrentRuntimeConfig.shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional"; - - EffectMeta em; - - // load internal effects - em.path = ":/internalshaders"; - - em.type = EFFECT_TYPE_EFFECT; - em.subtype = EFFECT_TYPE_AUDIO; - - em.name = "Volume"; - em.internal = EFFECT_INTERNAL_VOLUME; - effects.append(em); - - em.name = "Pan"; - em.internal = EFFECT_INTERNAL_PAN; - effects.append(em); - -#ifndef NOVST - em.name = "VST Plugin 2.x"; - em.internal = EFFECT_INTERNAL_VST; - effects.append(em); -#endif - - em.name = "Tone"; - em.internal = EFFECT_INTERNAL_TONE; - effects.append(em); - - em.name = "Noise"; - em.internal = EFFECT_INTERNAL_NOISE; - effects.append(em); - - em.name = "Fill Left/Right"; - em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT; - effects.append(em); - - em.subtype = EFFECT_TYPE_VIDEO; - - em.name = "Transform"; - em.category = "Distort"; - em.internal = EFFECT_INTERNAL_TRANSFORM; - effects.append(em); - - em.name = "Corner Pin"; - em.internal = EFFECT_INTERNAL_CORNERPIN; - effects.append(em); - - /*em.name = "Mask"; - em.internal = EFFECT_INTERNAL_MASK; - effects.append(em);*/ - - em.name = "Shake"; - em.internal = EFFECT_INTERNAL_SHAKE; - effects.append(em); - - em.name = "Text"; - em.category = "Render"; - em.internal = EFFECT_INTERNAL_TEXT; - effects.append(em); - - em.name = "Timecode"; - em.internal = EFFECT_INTERNAL_TIMECODE; - effects.append(em); - - em.name = "Solid"; - em.internal = EFFECT_INTERNAL_SOLID; - effects.append(em); - - // internal transitions - em.type = EFFECT_TYPE_TRANSITION; - em.category = ""; - - em.name = "Cross Dissolve"; - em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE; - effects.append(em); - - em.subtype = EFFECT_TYPE_AUDIO; - - em.name = "Linear Fade"; - em.internal = TRANSITION_INTERNAL_LINEARFADE; - effects.append(em); - - em.name = "Exponential Fade"; - em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE; - effects.append(em); - - em.name = "Logarithmic Fade"; - em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE; - effects.append(em); -} - -void load_shader_effects() { - QList effects_paths = get_effects_paths(); - - for (int h=0;h entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); - for (int i=0;istart(); -} - -#ifndef NOFREI0R -void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector& loaded_names) { - QDir search_dir(dir); - if (search_dir.exists()) { - QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); - for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info")); - if (get_info_func != nullptr) { - f0r_plugin_info_t info; - get_info_func(&info); - - if (!loaded_names.contains(info.name) - && info.plugin_type == F0R_PLUGIN_TYPE_FILTER - && info.color_model == F0R_COLOR_MODEL_RGBA8888) { - em.name = info.name; - em.path = dir; - em.filename = entry_list.at(j); - em.tooltip = QString("%1\n%2\n%3\n%4").arg(em.name, info.author, info.explanation, em.filename); - - loaded_names.append(em.name); - - effects.append(em); - } -// qDebug() << "Found:" << info.name << "by" << info.author; - } - LibClose(effect); - } -// qDebug() << search_dir.filePath(entry_list.at(j)); - } - } - } -} - -void load_frei0r_effects() { - QList effect_dirs = get_effects_paths(); - - // add defined paths for frei0r plugins on unix -#if defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__) - effect_dirs.prepend("/usr/lib/frei0r-1"); - effect_dirs.prepend("/usr/local/lib/frei0r-1"); - effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib"); -#endif - - QString env_path(qgetenv("FREI0R_PATH")); - if (!env_path.isEmpty()) effect_dirs.append(env_path); - - QVector loaded_names; - - // search for paths - EffectMeta em; - em.category = "Frei0r"; - em.type = EFFECT_TYPE_EFFECT; - em.subtype = EFFECT_TYPE_VIDEO; - em.internal = EFFECT_INTERNAL_FREI0R; - - for (int i=0;ieffects_loaded.lock(); -} - -void EffectInit::run() { - qInfo() << "Initializing effects..."; - load_internal_effects(); - load_shader_effects(); -#ifndef NOFREI0R - load_frei0r_effects(); -#endif - panel_effect_controls->effects_loaded.unlock(); - qInfo() << "Finished initializing effects"; -} diff --git a/project/footage.cpp b/project/footage.cpp index d4654410d..bde8c4c20 100644 --- a/project/footage.cpp +++ b/project/footage.cpp @@ -23,9 +23,9 @@ #include #include #include -#include "io/previewgenerator.h" -#include "project/clip.h" +#include "project/previewgenerator.h" +#include "timeline/clip.h" Footage::Footage() { ready = (false); @@ -38,56 +38,56 @@ Footage::Footage() { proxy = (false); start_number = 0; - ready_lock.lock(); + ready_lock.lock(); } Footage::~Footage() { - reset(); + reset(); } void Footage::reset() { - if (preview_gen != nullptr) { - preview_gen->cancel(); - } - video_tracks.clear(); - audio_tracks.clear(); - ready = false; + if (preview_gen != nullptr) { + preview_gen->cancel(); + } + video_tracks.clear(); + audio_tracks.clear(); + ready = false; } long Footage::get_length_in_frames(double frame_rate) { if (length >= 0) { return qFloor((double(length) / double(AV_TIME_BASE)) * frame_rate / speed); } - return 0; + return 0; } FootageStream* Footage::get_stream_from_file_index(bool video, int index) { - if (video) { - for (int i=0;i>1; - int sqx = (diff < 0) ? -diff : 0; - int sqy = (diff > 0) ? diff : 0; - p.drawImage(sqx, sqy, video_preview); - p.end(); - video_preview_square = QIcon(pixmap); + // generate square version for QListView? + int square_size = qMax(video_preview.width(), video_preview.height()); + QPixmap pixmap(square_size, square_size); + pixmap.fill(Qt::transparent); + QPainter p(&pixmap); + int diff = (video_preview.width() - video_preview.height())>>1; + int sqx = (diff < 0) ? -diff : 0; + int sqy = (diff > 0) ? diff : 0; + p.drawImage(sqx, sqy, video_preview); + p.end(); + video_preview_square = QIcon(pixmap); } diff --git a/project/footage.h b/project/footage.h index ffbd1a001..04ff51706 100644 --- a/project/footage.h +++ b/project/footage.h @@ -34,7 +34,7 @@ extern "C" { #include #include -#include "project/marker.h" +#include "timeline/marker.h" enum VideoInterlacingMode { VIDEO_PROGRESSIVE, diff --git a/io/loadthread.cpp b/project/loadthread.cpp similarity index 99% rename from io/loadthread.cpp rename to project/loadthread.cpp index 0e3582830..eca71eb90 100644 --- a/io/loadthread.cpp +++ b/project/loadthread.cpp @@ -20,19 +20,19 @@ #include "loadthread.h" -#include "oliveglobal.h" +#include "global/global.h" -#include "mainwindow.h" +#include "ui/mainwindow.h" #include "panels/panels.h" #include "project/projectelements.h" -#include "io/config.h" +#include "global/config.h" #include "rendering/renderfunctions.h" -#include "io/previewgenerator.h" +#include "project/previewgenerator.h" #include "effects/internal/voideffect.h" -#include "debug.h" +#include "global/debug.h" #include #include diff --git a/io/loadthread.h b/project/loadthread.h similarity index 98% rename from io/loadthread.h rename to project/loadthread.h index 5888bb99f..84badc682 100644 --- a/io/loadthread.h +++ b/project/loadthread.h @@ -29,6 +29,7 @@ #include #include "project/projectelements.h" +#include "timeline/clip.h" class LoadThread : public QThread { diff --git a/project/media.cpp b/project/media.cpp index bc0afa64b..2e56801ec 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -20,25 +20,24 @@ #include "media.h" -#include "footage.h" -#include "sequence.h" -#include "undo.h" -#include "io/config.h" -#include "panels/viewer.h" -#include "panels/project.h" -#include "ui/icons.h" -#include "projectmodel.h" - -#include -#include - -#include "debug.h" - extern "C" { #include #include } +#include +#include + +#include "footage.h" +#include "timeline/sequence.h" +#include "undo/undo.h" +#include "global/config.h" +#include "panels/viewer.h" +#include "panels/project.h" +#include "ui/icons.h" +#include "projectmodel.h" +#include "global/debug.h" + QString get_interlacing_name(int interlacing) { switch (interlacing) { case VIDEO_PROGRESSIVE: return QCoreApplication::translate("InterlacingName", "None (Progressive)"); diff --git a/project/media.h b/project/media.h index 3dd26f044..77d96519b 100644 --- a/project/media.h +++ b/project/media.h @@ -25,7 +25,7 @@ #include #include -#include "project/marker.h" +#include "timeline/marker.h" #include "project/footage.h" enum MediaType { diff --git a/io/previewgenerator.cpp b/project/previewgenerator.cpp similarity index 96% rename from io/previewgenerator.cpp rename to project/previewgenerator.cpp index 1f9143a3a..3597e744b 100644 --- a/io/previewgenerator.cpp +++ b/project/previewgenerator.cpp @@ -25,9 +25,9 @@ #include "project/footage.h" #include "panels/viewer.h" #include "panels/project.h" -#include "io/config.h" -#include "io/path.h" -#include "debug.h" +#include "global/config.h" +#include "global/path.h" +#include "global/debug.h" #include #include diff --git a/io/previewgenerator.h b/project/previewgenerator.h similarity index 100% rename from io/previewgenerator.h rename to project/previewgenerator.h diff --git a/project/projectelements.h b/project/projectelements.h index 2ec53d769..6868b19c3 100644 --- a/project/projectelements.h +++ b/project/projectelements.h @@ -30,12 +30,5 @@ // includes elements the user can use in a project #include "media.h" #include "footage.h" -#include "sequence.h" - -// includes elements the user can use in a sequence -#include "clip.h" -#include "transition.h" -#include "marker.h" -#include "effect.h" #endif // PROJECTELEMENTS_H diff --git a/project/projectfilter.cpp b/project/projectfilter.cpp index 72000a046..5bc330364 100644 --- a/project/projectfilter.cpp +++ b/project/projectfilter.cpp @@ -21,21 +21,21 @@ #include "projectfilter.h" #include "project/media.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include ProjectFilter::ProjectFilter(QObject *parent) : - QSortFilterProxyModel(parent), - show_sequences(true) + QSortFilterProxyModel(parent), + show_sequences(true) {} bool ProjectFilter::get_show_sequences() { - return show_sequences; + return show_sequences; } void ProjectFilter::set_show_sequences(bool b) { - show_sequences = b; + show_sequences = b; invalidateFilter(); } @@ -50,11 +50,11 @@ bool ProjectFilter::filterAcceptsRow(int source_row, const QModelIndex &source_p Media* media = static_cast(index.internalPointer()); // hide sequences if show_sequences is false - if (!show_sequences) { - if (media != nullptr && media->get_type() == MEDIA_TYPE_SEQUENCE) { - return false; - } - } + if (!show_sequences) { + if (media != nullptr && media->get_type() == MEDIA_TYPE_SEQUENCE) { + return false; + } + } // filter by search filter string if (!search_filter.isEmpty()) { @@ -80,5 +80,5 @@ bool ProjectFilter::filterAcceptsRow(int source_row, const QModelIndex &source_p } } - return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index b1b5022c4..8c4c66f34 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -24,7 +24,7 @@ #include "panels/viewer.h" #include "ui/viewerwidget.h" #include "project/media.h" -#include "debug.h" +#include "global/debug.h" ProjectModel olive::project_model; diff --git a/io/proxygenerator.cpp b/project/proxygenerator.cpp similarity index 96% rename from io/proxygenerator.cpp rename to project/proxygenerator.cpp index cb37a5a0a..6a6cd11ce 100644 --- a/io/proxygenerator.cpp +++ b/project/proxygenerator.cpp @@ -20,9 +20,9 @@ #include "proxygenerator.h" -#include "io/path.h" -#include "io/previewgenerator.h" -#include "mainwindow.h" +#include "global/path.h" +#include "project/previewgenerator.h" +#include "ui/mainwindow.h" #include #include diff --git a/io/proxygenerator.h b/project/proxygenerator.h similarity index 100% rename from io/proxygenerator.h rename to project/proxygenerator.h diff --git a/project/sourcescommon.cpp b/project/sourcescommon.cpp index 0156520e0..524a1b3f7 100644 --- a/project/sourcescommon.cpp +++ b/project/sourcescommon.cpp @@ -23,19 +23,19 @@ #include "ui/menuhelper.h" #include "panels/panels.h" #include "project/media.h" -#include "project/undo.h" +#include "undo/undo.h" #include "rendering/renderfunctions.h" #include "panels/timeline.h" #include "panels/project.h" #include "project/footage.h" #include "panels/viewer.h" #include "project/projectfilter.h" -#include "project/sequence.h" -#include "io/config.h" +#include "timeline/sequence.h" +#include "global/config.h" #include "dialogs/proxydialog.h" #include "ui/viewerwidget.h" -#include "io/proxygenerator.h" -#include "mainwindow.h" +#include "project/proxygenerator.h" +#include "ui/mainwindow.h" #include #include diff --git a/rendering/audio.cpp b/rendering/audio.cpp index a5e4b49a6..68a5eea9e 100644 --- a/rendering/audio.cpp +++ b/rendering/audio.cpp @@ -20,16 +20,16 @@ #include "audio.h" -#include "oliveglobal.h" +#include "global/global.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include "panels/panels.h" -#include "io/config.h" +#include "global/config.h" #include "ui/audiomonitor.h" #include "rendering/renderfunctions.h" -#include "debug.h" +#include "global/debug.h" #include #include diff --git a/rendering/audio.h b/rendering/audio.h index ba6aba7b5..6644039bb 100644 --- a/rendering/audio.h +++ b/rendering/audio.h @@ -29,22 +29,22 @@ #include #include -#include "project/sequence.h" +#include "timeline/sequence.h" class AudioSenderThread : public QThread { - Q_OBJECT + Q_OBJECT public: - AudioSenderThread(); - void run(); - void stop(); - QWaitCondition cond; - bool close; - QMutex lock; + AudioSenderThread(); + void run(); + void stop(); + QWaitCondition cond; + bool close; + QMutex lock; public slots: - void notifyReceiver(); + void notifyReceiver(); private: - QVector samples; - int send_audio_to_output(qint64 offset, int max); + QVector samples; + int send_audio_to_output(qint64 offset, int max); }; double log_volume(double linear); diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index 7c2460eed..b1f32e46c 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -37,8 +37,8 @@ #include "rendering/audio.h" #include "rendering/renderfunctions.h" #include "panels/panels.h" -#include "io/config.h" -#include "debug.h" +#include "global/config.h" +#include "global/debug.h" // Enable verbose audio messages - good for debugging reversed audio //#define AUDIOWARNINGS diff --git a/io/exportthread.cpp b/rendering/exportthread.cpp similarity index 96% rename from io/exportthread.cpp rename to rendering/exportthread.cpp index 05fff530d..e224484f2 100644 --- a/io/exportthread.cpp +++ b/rendering/exportthread.cpp @@ -20,18 +20,16 @@ #include "exportthread.h" -#include "oliveglobal.h" - -#include "project/sequence.h" - +#include "global/global.h" +#include "timeline/sequence.h" #include "panels/panels.h" #include "ui/viewerwidget.h" #include "rendering/renderthread.h" #include "rendering/renderfunctions.h" #include "rendering/audio.h" -#include "mainwindow.h" -#include "debug.h" +#include "ui/mainwindow.h" +#include "global/debug.h" extern "C" { #include diff --git a/io/exportthread.h b/rendering/exportthread.h similarity index 100% rename from io/exportthread.h rename to rendering/exportthread.h diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 36286b355..da22f9ff3 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -34,19 +34,19 @@ extern "C" { namespace OCIO = OCIO_NAMESPACE; #endif -#include "project/clip.h" -#include "project/sequence.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" #include "project/media.h" -#include "project/effect.h" +#include "effects/effect.h" #include "project/footage.h" -#include "project/transition.h" +#include "effects/transition.h" #include "ui/collapsiblewidget.h" #include "rendering/audio.h" -#include "io/math.h" -#include "io/config.h" +#include "global/math.h" +#include "global/config.h" #include "panels/timeline.h" #include "panels/viewer.h" diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h index 21507c990..abea07c33 100644 --- a/rendering/renderfunctions.h +++ b/rendering/renderfunctions.h @@ -25,9 +25,8 @@ #include #include -#include "project/sequence.h" -#include "project/effect.h" - +#include "timeline/sequence.h" +#include "effects/effect.h" #include "panels/viewer.h" /** diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 7dc2f0715..5f828468a 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -31,7 +31,7 @@ namespace OCIO = OCIO_NAMESPACE; #endif #include "rendering/renderfunctions.h" -#include "project/sequence.h" +#include "timeline/sequence.h" RenderThread::RenderThread() : gizmos(nullptr), diff --git a/rendering/renderthread.h b/rendering/renderthread.h index 8f0d9c3a4..4a3a95144 100644 --- a/rendering/renderthread.h +++ b/rendering/renderthread.h @@ -29,8 +29,8 @@ #include #include -#include "project/sequence.h" -#include "project/effect.h" +#include "timeline/sequence.h" +#include "effects/effect.h" #include "rendering/framebufferobject.h" // copied from source code to OCIODisplay diff --git a/project/clip.cpp b/timeline/clip.cpp similarity index 95% rename from project/clip.cpp rename to timeline/clip.cpp index a1cef5d25..0a8a9d6b9 100644 --- a/project/clip.cpp +++ b/timeline/clip.cpp @@ -22,19 +22,19 @@ #include -#include "project/effect.h" -#include "project/transition.h" +#include "effects/effect.h" +#include "effects/transition.h" #include "project/footage.h" -#include "io/config.h" +#include "global/config.h" #include "rendering/cacher.h" #include "rendering/renderfunctions.h" #include "panels/project.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include "panels/timeline.h" #include "project/media.h" -#include "io/clipboard.h" -#include "undo.h" -#include "debug.h" +#include "project/clipboard.h" +#include "undo/undo.h" +#include "global/debug.h" const int kRGBAComponentCount = 4; diff --git a/project/clip.h b/timeline/clip.h similarity index 92% rename from project/clip.h rename to timeline/clip.h index f7b52da8a..cf8435966 100644 --- a/project/clip.h +++ b/timeline/clip.h @@ -30,11 +30,11 @@ #include "rendering/cacher.h" -#include "project/effect.h" -#include "project/transition.h" -#include "project/comboaction.h" +#include "effects/effect.h" +#include "effects/transition.h" +#include "undo/comboaction.h" #include "project/media.h" -#include "footage.h" +#include "project/footage.h" #include "marker.h" diff --git a/project/marker.cpp b/timeline/marker.cpp similarity index 93% rename from project/marker.cpp rename to timeline/marker.cpp index ef2cb5014..a05985741 100644 --- a/project/marker.cpp +++ b/timeline/marker.cpp @@ -20,11 +20,11 @@ #include "marker.h" -#include "io/config.h" -#include "project/undo.h" -#include "mainwindow.h" -#include "project/sequence.h" -#include "project/clip.h" +#include "global/config.h" +#include "undo/undo.h" +#include "ui/mainwindow.h" +#include "timeline/sequence.h" +#include "timeline/clip.h" #include "panels/panels.h" #include "panels/viewer.h" diff --git a/project/marker.h b/timeline/marker.h similarity index 100% rename from project/marker.h rename to timeline/marker.h diff --git a/project/selection.h b/timeline/selection.h similarity index 100% rename from project/selection.h rename to timeline/selection.h diff --git a/project/sequence.cpp b/timeline/sequence.cpp similarity index 95% rename from project/sequence.cpp rename to timeline/sequence.cpp index a604146db..6cd2967f3 100644 --- a/project/sequence.cpp +++ b/timeline/sequence.cpp @@ -23,8 +23,7 @@ #include #include "panels/panels.h" - -#include "debug.h" +#include "global/debug.h" Sequence::Sequence() { playhead = 0; diff --git a/project/sequence.h b/timeline/sequence.h similarity index 89% rename from project/sequence.h rename to timeline/sequence.h index 558ae3db2..8893b1362 100644 --- a/project/sequence.h +++ b/timeline/sequence.h @@ -24,10 +24,9 @@ #include #include -#include "project/clip.h" -#include "project/marker.h" -#include "project/transition.h" -#include "project/selection.h" +#include "clip.h" +#include "marker.h" +#include "selection.h" class Sequence { public: diff --git a/ui/audiomonitor.cpp b/ui/audiomonitor.cpp index 0e0f9f528..239deff00 100644 --- a/ui/audiomonitor.cpp +++ b/ui/audiomonitor.cpp @@ -20,7 +20,7 @@ #include "audiomonitor.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include "rendering/audio.h" #include "panels/panels.h" #include "panels/timeline.h" @@ -39,60 +39,60 @@ extern "C" { } AudioMonitor::AudioMonitor(QWidget *parent) : - QWidget(parent) + QWidget(parent) { - clear_timer.setInterval(500); - connect(&clear_timer, SIGNAL(timeout()), this, SLOT(clear())); + clear_timer.setInterval(500); + connect(&clear_timer, SIGNAL(timeout()), this, SLOT(clear())); } void AudioMonitor::set_value(const QVector &ivalues) { - values = ivalues; - update(); + values = ivalues; + update(); - QMetaObject::invokeMethod(&clear_timer, "start", Qt::QueuedConnection); + QMetaObject::invokeMethod(&clear_timer, "start", Qt::QueuedConnection); } void AudioMonitor::clear() { - clear_timer.stop(); + clear_timer.stop(); - values.fill(1); - update(); + values.fill(1); + update(); } void AudioMonitor::resizeEvent(QResizeEvent *e) { - gradient = QLinearGradient(QPoint(0, rect().top()), QPoint(0, rect().bottom())); - gradient.setColorAt(0, Qt::red); - gradient.setColorAt(0.25, Qt::yellow); - gradient.setColorAt(1, Qt::green); - QWidget::resizeEvent(e); + gradient = QLinearGradient(QPoint(0, rect().top()), QPoint(0, rect().bottom())); + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(0.25, Qt::yellow); + gradient.setColorAt(1, Qt::green); + QWidget::resizeEvent(e); } void AudioMonitor::paintEvent(QPaintEvent *) { - if (olive::ActiveSequence != nullptr && values.size() > 0) { - QPainter p(this); - int channel_x = AUDIO_MONITOR_GAP; - int channel_count = values.size(); - int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP; - int i; - for (i=0;i 0) { + QPainter p(this); + int channel_x = AUDIO_MONITOR_GAP; + int channel_count = values.size(); + int channel_width = (width()/channel_count) - AUDIO_MONITOR_GAP; + int i; + for (i=0;i #include -#include "project/clip.h" +#include "timeline/clip.h" #include "ui/menuhelper.h" #include "ui/keyframenavigator.h" +#include "panels/panels.h" EffectUI::EffectUI(Effect* e) : effect_(e) @@ -27,6 +28,8 @@ EffectUI::EffectUI(Effect* e) : int maximum_column = 0; + widgets_.resize(e->row_count()); + for (int i=0;irow_count();i++) { EffectRow* row = e->row(i); @@ -36,12 +39,16 @@ EffectUI::EffectUI(Effect* e) : layout_->addWidget(row_label, i, 0); + widgets_[i].resize(row->FieldCount()); + int column = 1; for (int j=0;jFieldCount();j++) { EffectField* field = row->Field(j); QWidget* widget = field->CreateWidget(); + widgets_[i][j] = widget; + layout_->addWidget(widget, i, column, 1, field->GetColumnSpan()); column += field->GetColumnSpan(); @@ -64,6 +71,7 @@ EffectUI::EffectUI(Effect* e) : connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); connect(nav, SIGNAL(keyframe_enabled_changed(bool)), row, SLOT(SetKeyframingEnabled(bool))); connect(nav, SIGNAL(clicked()), row, SLOT(FocusRow())); + connect(row, SIGNAL(KeyframingSetChanged(bool)), nav, SLOT(enable_keyframes(bool))); layout_->addWidget(nav, i, maximum_column); } @@ -76,10 +84,17 @@ Effect *EffectUI::GetEffect() return effect_; } -int EffectUI::GetRowPos(int row) -{ +int EffectUI::GetRowY(int row, QWidget* mapToWidget) { QLabel* row_label = labels_.at(row); - return mapToGlobal(row_label->rect().center()).y(); + return row_label->y() + + row_label->height() / 2 + + mapToWidget->mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() + - title_bar->height(); +} + +QWidget *EffectUI::Widget(int row, int field) +{ + return widgets_.at(row).at(field); } void EffectUI::show_context_menu(const QPoint& pos) { diff --git a/ui/effectui.h b/ui/effectui.h index 3191fc90c..81de6871e 100644 --- a/ui/effectui.h +++ b/ui/effectui.h @@ -2,7 +2,7 @@ #define EFFECTUI_H #include "collapsiblewidget.h" -#include "project/effect.h" +#include "effects/effect.h" class EffectUI : public CollapsibleWidget { Q_OBJECT @@ -11,7 +11,9 @@ public: Effect* GetEffect(); - int GetRowPos(int row); + int GetRowY(int row, QWidget *mapToWidget); + + QWidget* Widget(int row, int field); signals: void CutRequested(); void CopyRequested(); @@ -20,6 +22,7 @@ private: Effect* effect_; QGridLayout* layout_; QVector labels_; + QVector< QVector > widgets_; private slots: void show_context_menu(const QPoint&); }; diff --git a/ui/focusfilter.cpp b/ui/focusfilter.cpp index ae280ad04..d942279eb 100644 --- a/ui/focusfilter.cpp +++ b/ui/focusfilter.cpp @@ -21,7 +21,7 @@ #include "focusfilter.h" #include "panels/panels.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include "ui/timelineheader.h" FocusFilter olive::FocusFilter; diff --git a/ui/graphview.cpp b/ui/graphview.cpp index bc08d2a6c..f6b6cd124 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -26,18 +26,17 @@ #include #include -#include "io/config.h" +#include "global/config.h" #include "panels/panels.h" #include "panels/timeline.h" #include "panels/viewer.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include "ui/keyframedrawing.h" -#include "project/undo.h" -#include "project/effect.h" -#include "project/clip.h" +#include "undo/undo.h" +#include "effects/effect.h" +#include "timeline/clip.h" #include "ui/rectangleselect.h" - -#include "debug.h" +#include "global/debug.h" const double kGraphZoomSpeed = 0.05; @@ -702,7 +701,7 @@ void GraphView::mouseMoveEvent(QMouseEvent *event) { void GraphView::mouseReleaseEvent(QMouseEvent *) { if (click_add_proc) { - olive::UndoStack.push(new KeyframeFieldSet(click_add_field, click_add_key)); + olive::UndoStack.push(new KeyframeAdd(click_add_field, click_add_key)); } else if (moved_keys && selected_keys.size() > 0) { ComboAction* ca = new ComboAction(); switch (current_handle) { diff --git a/ui/graphview.h b/ui/graphview.h index bc1e96473..285048882 100644 --- a/ui/graphview.h +++ b/ui/graphview.h @@ -24,8 +24,8 @@ #include #include -#include "project/effectrow.h" -#include "project/effectfields.h" +#include "effects/effectrow.h" +#include "effects/effectfields.h" QColor get_curve_color(int index, int length); diff --git a/ui/keyframenavigator.h b/ui/keyframenavigator.h index b0141aeb1..772a1f8f7 100644 --- a/ui/keyframenavigator.h +++ b/ui/keyframenavigator.h @@ -32,8 +32,9 @@ class KeyframeNavigator : public QWidget public: KeyframeNavigator(QWidget* parent = nullptr, bool addLeftPad = true); ~KeyframeNavigator(); - void enable_keyframes(bool); + void enable_keyframe_toggle(bool); + void enable_keyframes(bool); signals: void goto_previous_key(); void toggle_key(); diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index b0a0beb46..7e9bff745 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -20,22 +20,22 @@ #include "keyframeview.h" -#include "project/effect.h" +#include "effects/effect.h" #include "ui/collapsiblewidget.h" #include "panels/panels.h" -#include "project/clip.h" +#include "timeline/clip.h" #include "panels/timeline.h" #include "ui/timelineheader.h" -#include "project/undo.h" +#include "undo/undo.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" -#include "project/sequence.h" +#include "timeline/sequence.h" #include "panels/grapheditor.h" #include "ui/keyframedrawing.h" #include "ui/clickablelabel.h" #include "ui/resizablescrollbar.h" #include "ui/rectangleselect.h" -#include "project/keyframe.h" +#include "effects/keyframe.h" #include "ui/graphview.h" #include @@ -124,7 +124,7 @@ void KeyframeView::paintEvent(QPaintEvent*) { for (int j=0;jrow_count();j++) { EffectRow* row = e->row(j); - int keyframe_y = container->GetRowPos(j); + int keyframe_y = container->GetRowY(j, this); QVector key_times; diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 439581789..614c8b556 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -20,11 +20,11 @@ #include "labelslider.h" -#include "project/undo.h" +#include "undo/undo.h" #include "panels/viewer.h" -#include "io/config.h" -#include "io/math.h" -#include "debug.h" +#include "global/config.h" +#include "global/math.h" +#include "global/debug.h" #include #include @@ -40,28 +40,33 @@ LabelSlider::LabelSlider(QWidget* parent) : QLabel(parent) { drag_proc = false; min_enabled = false; max_enabled = false; - set_color(); - set_default_cursor(); + SetColor(); + SetDefaultCursor(); internal_value = -1; set = false; - display_type = LABELSLIDER_NORMAL; + display_type = Normal; - set_default_value(0); + SetDefault(0); setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ShowContextMenu(const QPoint&))); } -void LabelSlider::set_frame_rate(double d) { +void LabelSlider::SetFrameRate(double d) { frame_rate = d; } -void LabelSlider::set_display_type(const DisplayType& type) { - display_type = type; - setText(valueToString()); +void LabelSlider::SetDecimalPlaces(int places) +{ + decimal_places = places; } -void LabelSlider::set_value(double v, bool userSet) { +void LabelSlider::SetDisplayType(const DisplayType& type) { + display_type = type; + setText(ValueToString()); +} + +void LabelSlider::SetValue(double v) { set = true; if (!qFuzzyCompare(v, internal_value)) { if (min_enabled && v < min_value) { @@ -72,32 +77,25 @@ void LabelSlider::set_value(double v, bool userSet) { internal_value = v; } - setText(valueToString()); - if (userSet) { - emit valueChanged(internal_value); - } + setText(ValueToString()); } } -bool LabelSlider::is_set() { - return set; -} - -bool LabelSlider::is_dragging() { +bool LabelSlider::IsDragging() { return drag_proc; } -QString LabelSlider::valueToString() { +QString LabelSlider::ValueToString() { double v = internal_value; if (qIsNaN(v)) { return "---"; } else { switch (display_type) { - case LABELSLIDER_FRAMENUMBER: + case FrameNumber: return frame_to_timecode(long(v), olive::CurrentConfig.timecode_view, frame_rate); - case LABELSLIDER_PERCENT: + case Percent: return QString::number((v*100), 'f', decimal_places).append("%"); - case LABELSLIDER_DECIBEL: + case Decibel: { QString db_str; @@ -120,15 +118,7 @@ QString LabelSlider::valueToString() { } } -double LabelSlider::getPreviousValue() { - return previous_value; -} - -void LabelSlider::set_previous_value() { - previous_value = internal_value; -} - -void LabelSlider::set_color(QString c) { +void LabelSlider::SetColor(QString c) { if (c.isEmpty()) c = "#ffc000"; setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}"); } @@ -137,20 +127,20 @@ double LabelSlider::value() { return internal_value; } -void LabelSlider::set_default_value(double v) { +void LabelSlider::SetDefault(double v) { default_value = v; if (!set) { - set_value(v, false); + SetValue(v); set = false; } } -void LabelSlider::set_minimum_value(double v) { +void LabelSlider::SetMinimum(double v) { min_value = v; min_enabled = true; } -void LabelSlider::set_maximum_value(double v) { +void LabelSlider::SetMaximum(double v) { max_value = v; max_enabled = true; } @@ -166,7 +156,7 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) { if (ev->modifiers() & Qt::AltModifier) { // reset to default - reset_to_default_value(); + ResetToDefault(); } else { @@ -174,7 +164,7 @@ void LabelSlider::mousePressEvent(QMouseEvent *ev) { if (qIsNaN(internal_value)) internal_value = 0; // hide the cursor and store information about it for dragging - set_active_cursor(); + SetActiveCursor(); drag_start = true; drag_start_x = cursor().pos().x(); @@ -206,7 +196,7 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) { // ctrl + drag drags in smaller increments if (event->modifiers() & Qt::ControlModifier) diff *= 0.01; - if (display_type == LABELSLIDER_PERCENT) { + if (display_type == Percent) { // we'll also need to drag in smaller increments for a percent value diff *= 0.01; @@ -215,7 +205,7 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) { // determine what the new value will be double new_value; - if (display_type == LABELSLIDER_DECIBEL) { + if (display_type == Decibel) { // we move in terms of dB for decibel display new_value = db_to_amplitude(amplitude_to_db(internal_value) + diff); @@ -227,7 +217,8 @@ void LabelSlider::mouseMoveEvent(QMouseEvent* event) { } // set internal value - set_value(new_value, true); + SetValue(new_value); + emit valueChanged(internal_value); // keep the cursor in the same location while dragging cursor().setPos(drag_start_x, drag_start_y); @@ -238,7 +229,7 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) { if (drag_start) { // unhide cursor - set_default_cursor(); + SetDefaultCursor(); drag_start = false; @@ -253,49 +244,47 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) { } else { - prompt_for_value(); + ShowDialog(); } } } -void LabelSlider::set_default_cursor() { +void LabelSlider::SetDefaultCursor() { setCursor(Qt::SizeHorCursor); } -void LabelSlider::set_active_cursor() { +void LabelSlider::SetActiveCursor() { setCursor(Qt::BlankCursor); } -void LabelSlider::show_context_menu(const QPoint &pos) +void LabelSlider::ShowContextMenu(const QPoint &pos) { QMenu menu(this); - menu.addAction(tr("&Edit"), this, SLOT(prompt_for_value())); + menu.addAction(tr("&Edit"), this, SLOT(ShowDialog())); menu.addSeparator(); - menu.addAction(tr("&Reset to Default"), this, SLOT(reset_to_default_value())); + menu.addAction(tr("&Reset to Default"), this, SLOT(ResetToDefault())); menu.exec(mapToGlobal(pos)); } -void LabelSlider::reset_to_default_value() +void LabelSlider::ResetToDefault() { // if the value is not already default, and there is a default to set if (!qFuzzyCompare(internal_value, default_value) && !qIsNaN(default_value)) { - // cache current value - set_previous_value(); - // set back to default - set_value(default_value, true); + SetValue(default_value); + emit valueChanged(internal_value); } } -void LabelSlider::prompt_for_value() +void LabelSlider::ShowDialog() { // if the user didn't actually drag, and just clicked in one place, // we instead present a dialog prompt for the user to enter a @@ -303,7 +292,7 @@ void LabelSlider::prompt_for_value() double d = internal_value; - if (display_type == LABELSLIDER_FRAMENUMBER) { + if (display_type == FrameNumber) { // ask the user to enter a timecode QString s = QInputDialog::getText( @@ -311,7 +300,7 @@ void LabelSlider::prompt_for_value() tr("Set Value"), tr("New value:"), QLineEdit::Normal, - valueToString() + ValueToString() ); if (s.isEmpty()) return; @@ -325,9 +314,9 @@ void LabelSlider::prompt_for_value() // value to show double shown_value = internal_value; - if (display_type == LABELSLIDER_PERCENT) { + if (display_type == Percent) { shown_value *= 100; - } else if (display_type == LABELSLIDER_DECIBEL) { + } else if (display_type == Decibel) { shown_value = amplitude_to_db(shown_value); } @@ -336,7 +325,7 @@ void LabelSlider::prompt_for_value() if (min_enabled) { // if this field has a minimum value set, use it shown_minimum_value = min_value; - } else if (display_type == LABELSLIDER_DECIBEL) { + } else if (display_type == Decibel) { // minimum decibel amount is -96db shown_minimum_value = -96; } else { @@ -358,16 +347,16 @@ void LabelSlider::prompt_for_value() if (!ok) return; // convert shown value back to internal value - if (display_type == LABELSLIDER_PERCENT) { + if (display_type == Percent) { d *= 0.01; - } else if (display_type == LABELSLIDER_DECIBEL) { + } else if (display_type == Decibel) { d = db_to_amplitude(d); } } // if the value actually changed, trigger a change event if (!qFuzzyCompare(d, internal_value)) { - set_previous_value(); - set_value(d, true); + SetValue(d); + emit valueChanged(internal_value); } } diff --git a/ui/labelslider.h b/ui/labelslider.h index a0ddc6a02..e7550513c 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -37,20 +37,66 @@ public: LabelSlider(QWidget* parent = nullptr); /** - * @brief Set the display frame rate + * @brief Set the value + * @param v * - * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the - * timecode will be in. + * Value to set to. * - * @param d + * @param userSet + * + * **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The + * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and + * **FALSE** will not. */ - void set_frame_rate(double d); + void SetValue(double v); + + /** + * @brief Set the default value + * + * If a default value is set, alt+clicking the LabelSlider will return to the default value. + * + * @param v + * + * Value to set as default + */ + void SetDefault(double v); + + /** + * @brief Set the minimum value + * + * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than + * the minimum, it will automatically snap to the minimum. + * + * @param v + * + * Value to set as minimum + */ + void SetMinimum(double v); + + /** + * @brief Set the maximum value + * + * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than + * the maximum, it will automatically snap to the maximum. + * + * @param v + * + * Value to set as maximum + */ + void SetMaximum(double v); + + /** + * @brief Returns the internal value as a double + * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will + * return as 400%, and a timecode will return as a frame number. + */ + double value(); enum DisplayType { - LABELSLIDER_NORMAL, - LABELSLIDER_FRAMENUMBER, - LABELSLIDER_PERCENT, - LABELSLIDER_DECIBEL + Normal, + FrameNumber, + Percent, + Decibel }; /** @@ -67,107 +113,13 @@ public: * * The display type to set to. */ - void set_display_type(const DisplayType& type); - - /** - * @brief Set the value - * @param v - * - * Value to set to. - * - * @param userSet - * - * **TRUE** if this was called through a user action, **FALSE** if this was called through some other way. The - * only difference is **TRUE** will emit a signal (valueChanged()) indicating that the value has changed, and - * **FALSE** will not. - */ - void set_value(double v, bool userSet); - - /** - * @brief Set the default value - * - * If a default value is set, alt+clicking the LabelSlider will return to the default value. - * - * @param v - * - * Value to set as default - */ - void set_default_value(double v); - - /** - * @brief Set the minimum value - * - * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than - * the minimum, it will automatically snap to the minimum. - * - * @param v - * - * Value to set as minimum - */ - void set_minimum_value(double v); - - /** - * @brief Set the maximum value - * - * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than - * the maximum, it will automatically snap to the maximum. - * - * @param v - * - * Value to set as maximum - */ - void set_maximum_value(double v); - - /** - * @brief Returns the internal value as a double - * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will - * return as 400%, and a timecode will return as a frame number. - */ - double value(); - - /** - * @brief Returns whether a value has been set or not - * - * If a value has been entered by any means (i.e. if set_value() was called), this will be **TRUE**. If set_value() - * has not been called and is_set() is **FALSE**, calling set_default_value() will automatically set the value - * to the default value WITHOUT changing the is_set() state (i.e. it will still be **FALSE** and calling - * set_default_value() again will change the current value again unless it's been changed through some other means - * in that time). - * - * @return **TRUE** if a value has been set, **FALSE** if not. - */ - bool is_set(); + void SetDisplayType(const DisplayType& type); /** * @brief Returns whether the user is currently dragging * @return **TRUE** if the user is dragging, **FALSE** if not. */ - bool is_dragging(); - - /** - * @brief Convert the internal value to a displayed string according to `display_type` - * @return The internal value as a string - */ - QString valueToString(); - - /** - * @brief Returns whatever value was set before the last set_value() - * - * For various reasons (largely undo capabilities) it is helpful to retrieve whatever the value was before the - * current one. If the user dragged the current value, this will return the value just before the user started - * dragging. - * - * @return The previous value - */ - double getPreviousValue(); - - /** - * @brief Updates previous value - * - * Called internally to store the current value as the previous value in anticipation of an upcoming value change. - * Can also be called externally (mainly for dragged EffectGizmos) in anticipation of an external change. - */ - void set_previous_value(); + bool IsDragging(); /** * @brief Set the display color @@ -175,24 +127,43 @@ public: * * Color to set to */ - void set_color(QString c = nullptr); + void SetColor(QString c = nullptr); + + /** + * @brief Set the display frame rate + * + * If the `display_type` is set to LABELSLIDER_FRAMENUMBER, this function sets how many frames per second the + * timecode will be in. + * + * @param d + */ + void SetFrameRate(double d); /** * @brief Set how many decimal places to show for a floating-point number * * Defaults to 1 */ - int decimal_places; + void SetDecimalPlaces(int places); protected: void mousePressEvent(QMouseEvent *ev); void mouseMoveEvent(QMouseEvent *ev); void mouseReleaseEvent(QMouseEvent *ev); private: + + /** + * @brief Convert the internal value to a displayed string according to `display_type` + * @return The internal value as a string + */ + QString ValueToString(); + double default_value; double internal_value; double drag_start_value; double previous_value; + int decimal_places; + bool min_enabled; double min_value; bool max_enabled; @@ -212,12 +183,12 @@ private: /** * @brief Internal function to set the standard cursor (usually SizeHorCursor) */ - void set_default_cursor(); + void SetDefaultCursor(); /** * @brief Internal function to set the cursor while dragging (usually NoCursor aka invisible) */ - void set_active_cursor(); + void SetActiveCursor(); private slots: /** * @brief Context menu slot to be connected to QWidget::customContextMenuRequested(const QPoint&) @@ -226,12 +197,12 @@ private slots: * * Current cursor position */ - void show_context_menu(const QPoint& pos); + void ShowContextMenu(const QPoint& pos); /** * @brief Slot to reset current value to the default value */ - void reset_to_default_value(); + void ResetToDefault(); /** * @brief Show prompt asking for value @@ -240,7 +211,7 @@ private slots: * Will show an input dialog asking for a new value to be entered manually. Asks for units in the selected * display type and converts them back to the internal value type. */ - void prompt_for_value(); + void ShowDialog(); signals: /** * @brief valueChanged signal diff --git a/mainwindow.cpp b/ui/mainwindow.cpp similarity index 97% rename from mainwindow.cpp rename to ui/mainwindow.cpp index ad4d885c2..9c14f7da4 100644 --- a/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -20,16 +20,18 @@ #include "mainwindow.h" -#include "oliveglobal.h" +#include "global/global.h" #include "ui/menuhelper.h" #include "project/projectelements.h" +#include "timeline/clip.h" -#include "io/config.h" -#include "io/path.h" -#include "io/proxygenerator.h" +#include "global/config.h" +#include "global/path.h" +#include "global/debug.h" +#include "project/proxygenerator.h" #include "project/projectfilter.h" #include "ui/sourcetable.h" @@ -47,8 +49,6 @@ #include "rendering/audio.h" #include "rendering/renderfunctions.h" -#include "debug.h" - #include #include #include diff --git a/mainwindow.h b/ui/mainwindow.h similarity index 100% rename from mainwindow.h rename to ui/mainwindow.h diff --git a/ui/menuhelper.cpp b/ui/menuhelper.cpp index aad6a8fac..859f5e493 100644 --- a/ui/menuhelper.cpp +++ b/ui/menuhelper.cpp @@ -25,10 +25,10 @@ #include #include -#include "io/config.h" -#include "io/clipboard.h" -#include "mainwindow.h" -#include "oliveglobal.h" +#include "global/config.h" +#include "project/clipboard.h" +#include "ui/mainwindow.h" +#include "global/global.h" #include "panels/panels.h" #include "ui/focusfilter.h" diff --git a/ui/scrollarea.cpp b/ui/scrollarea.cpp index 24d731545..4249a39f3 100644 --- a/ui/scrollarea.cpp +++ b/ui/scrollarea.cpp @@ -23,7 +23,7 @@ #include #include -#include "io/config.h" +#include "global/config.h" #include "panels/panels.h" #include "panels/timeline.h" diff --git a/ui/sourceiconview.cpp b/ui/sourceiconview.cpp index f8f6bad82..66c62e6cf 100644 --- a/ui/sourceiconview.cpp +++ b/ui/sourceiconview.cpp @@ -25,65 +25,65 @@ #include "panels/project.h" #include "project/media.h" #include "project/sourcescommon.h" -#include "debug.h" +#include "global/debug.h" SourceIconView::SourceIconView(QWidget *parent) : QListView(parent) { - setSelectionMode(QAbstractItemView::ExtendedSelection); - setResizeMode(QListView::Adjust); - setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&))); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); + setSelectionMode(QAbstractItemView::ExtendedSelection); + setResizeMode(QListView::Adjust); + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); } void SourceIconView::show_context_menu() { - project_parent->sources_common->show_context_menu(this, selectedIndexes()); + project_parent->sources_common->show_context_menu(this, selectedIndexes()); } void SourceIconView::item_click(const QModelIndex& index) { - if (selectedIndexes().size() == 1 && index.column() == 0) { - project_parent->sources_common->item_click(project_parent->item_to_media(index), index); - } + if (selectedIndexes().size() == 1 && index.column() == 0) { + project_parent->sources_common->item_click(project_parent->item_to_media(index), index); + } } void SourceIconView::mousePressEvent(QMouseEvent* event) { - project_parent->sources_common->mousePressEvent(event); - if (!indexAt(event->pos()).isValid()) selectionModel()->clear(); - QListView::mousePressEvent(event); + project_parent->sources_common->mousePressEvent(event); + if (!indexAt(event->pos()).isValid()) selectionModel()->clear(); + QListView::mousePressEvent(event); } void SourceIconView::dragEnterEvent(QDragEnterEvent *event) { - if (event->mimeData()->hasUrls()) { - event->acceptProposedAction(); - } else { - QListView::dragEnterEvent(event); - } + if (event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } else { + QListView::dragEnterEvent(event); + } } void SourceIconView::dragMoveEvent(QDragMoveEvent *event) { - if (event->mimeData()->hasUrls()) { - event->acceptProposedAction(); - } else { - QListView::dragMoveEvent(event); - } + if (event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } else { + QListView::dragMoveEvent(event); + } } void SourceIconView::dropEvent(QDropEvent* event) { - QModelIndex drop_item = indexAt(event->pos()); - if (!drop_item.isValid()) drop_item = rootIndex(); - project_parent->sources_common->dropEvent(this, event, drop_item, selectedIndexes()); + QModelIndex drop_item = indexAt(event->pos()); + if (!drop_item.isValid()) drop_item = rootIndex(); + project_parent->sources_common->dropEvent(this, event, drop_item, selectedIndexes()); } void SourceIconView::mouseDoubleClickEvent(QMouseEvent *) { - bool default_behavior = true; - if (selectedIndexes().size() == 1) { - Media* m = project_parent->item_to_media(selectedIndexes().at(0)); - if (m->get_type() == MEDIA_TYPE_FOLDER) { - default_behavior = false; - setRootIndex(selectedIndexes().at(0)); - emit changed_root(); - } - } - if (default_behavior) { + bool default_behavior = true; + if (selectedIndexes().size() == 1) { + Media* m = project_parent->item_to_media(selectedIndexes().at(0)); + if (m->get_type() == MEDIA_TYPE_FOLDER) { + default_behavior = false; + setRootIndex(selectedIndexes().at(0)); + emit changed_root(); + } + } + if (default_behavior) { project_parent->sources_common->mouseDoubleClickEvent(selectedIndexes()); - } + } } diff --git a/ui/sourcetable.cpp b/ui/sourcetable.cpp index 9f88b2779..a421cd80b 100644 --- a/ui/sourcetable.cpp +++ b/ui/sourcetable.cpp @@ -26,13 +26,13 @@ #include "panels/viewer.h" #include "panels/panels.h" #include "rendering/renderfunctions.h" -#include "project/undo.h" -#include "project/sequence.h" +#include "undo/undo.h" +#include "timeline/sequence.h" #include "mainwindow.h" -#include "io/config.h" +#include "global/config.h" #include "project/media.h" #include "project/sourcescommon.h" -#include "debug.h" +#include "global/debug.h" #include #include @@ -46,30 +46,30 @@ #include SourceTable::SourceTable(QWidget* parent) : QTreeView(parent) { - setSortingEnabled(true); - setAcceptDrops(true); - sortByColumn(0, Qt::AscendingOrder); - setContextMenuPolicy(Qt::CustomContextMenu); - setEditTriggers(QAbstractItemView::NoEditTriggers); - setDragDropMode(QAbstractItemView::DragDrop); - setSelectionMode(QAbstractItemView::ExtendedSelection); - connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&))); - connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); + setSortingEnabled(true); + setAcceptDrops(true); + sortByColumn(0, Qt::AscendingOrder); + setContextMenuPolicy(Qt::CustomContextMenu); + setEditTriggers(QAbstractItemView::NoEditTriggers); + setDragDropMode(QAbstractItemView::DragDrop); + setSelectionMode(QAbstractItemView::ExtendedSelection); + connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(item_click(const QModelIndex&))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); } void SourceTable::show_context_menu() { - project_parent->sources_common->show_context_menu(this, selectionModel()->selectedRows()); + project_parent->sources_common->show_context_menu(this, selectionModel()->selectedRows()); } void SourceTable::item_click(const QModelIndex& index) { - if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) { - project_parent->sources_common->item_click(project_parent->item_to_media(index), index); - } + if (selectionModel()->selectedRows().size() == 1 && index.column() == 0) { + project_parent->sources_common->item_click(project_parent->item_to_media(index), index); + } } void SourceTable::mousePressEvent(QMouseEvent* event) { - project_parent->sources_common->mousePressEvent(event); - QTreeView::mousePressEvent(event); + project_parent->sources_common->mousePressEvent(event); + QTreeView::mousePressEvent(event); } void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) { @@ -77,21 +77,21 @@ void SourceTable::mouseDoubleClickEvent(QMouseEvent* ) { } void SourceTable::dragEnterEvent(QDragEnterEvent *event) { - if (event->mimeData()->hasUrls()) { - event->acceptProposedAction(); - } else { - QTreeView::dragEnterEvent(event); - } + if (event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } else { + QTreeView::dragEnterEvent(event); + } } void SourceTable::dragMoveEvent(QDragMoveEvent *event) { - if (event->mimeData()->hasUrls()) { - event->acceptProposedAction(); - } else { - QTreeView::dragMoveEvent(event); - } + if (event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } else { + QTreeView::dragMoveEvent(event); + } } void SourceTable::dropEvent(QDropEvent* event) { - project_parent->sources_common->dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows()); + project_parent->sources_common->dropEvent(this, event, indexAt(event->pos()), selectionModel()->selectedRows()); } diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index f32621ea7..510132704 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -23,13 +23,13 @@ #include "mainwindow.h" #include "panels/panels.h" #include "panels/timeline.h" -#include "project/sequence.h" -#include "project/undo.h" +#include "timeline/sequence.h" +#include "undo/undo.h" #include "project/media.h" #include "panels/viewer.h" -#include "io/config.h" +#include "global/config.h" #include "ui/menuhelper.h" -#include "debug.h" +#include "global/debug.h" #include #include diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index a9a4ea197..af6f142c8 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -20,15 +20,15 @@ #include "timelinewidget.h" -#include "oliveglobal.h" +#include "global/global.h" #include "panels/panels.h" #include "project/projectelements.h" #include "rendering/audio.h" -#include "io/config.h" +#include "global/config.h" #include "ui/sourcetable.h" #include "ui/sourceiconview.h" -#include "project/undo.h" +#include "undo/undo.h" #include "ui/viewerwidget.h" #include "ui/resizablescrollbar.h" #include "dialogs/newsequencedialog.h" @@ -39,9 +39,9 @@ #include "ui/menuhelper.h" #include "ui/focusfilter.h" #include "dialogs/clippropertiesdialog.h" -#include "debug.h" +#include "global/debug.h" -#include "project/effect.h" +#include "effects/effect.h" #include "effects/internal/solideffect.h" #include "effects/internal/texteffect.h" diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index 00fce1c4d..2965dd37c 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -28,11 +28,11 @@ #include #include -#include "project/sequence.h" -#include "project/clip.h" +#include "timeline/sequence.h" +#include "timeline/clip.h" #include "project/footage.h" #include "project/media.h" -#include "project/undo.h" +#include "undo/undo.h" #include "timelinetools.h" class Timeline; diff --git a/ui/viewercontainer.cpp b/ui/viewercontainer.cpp index c247ae0f6..9f9d62367 100644 --- a/ui/viewercontainer.cpp +++ b/ui/viewercontainer.cpp @@ -28,67 +28,67 @@ #include "viewerwidget.h" #include "panels/viewer.h" -#include "project/sequence.h" -#include "debug.h" +#include "timeline/sequence.h" +#include "global/debug.h" // enforces aspect ratio ViewerContainer::ViewerContainer(QWidget *parent) : - QWidget(parent), - fit(true), - child(nullptr) + QWidget(parent), + fit(true), + child(nullptr) { - horizontal_scrollbar = new QScrollBar(Qt::Horizontal, this); - vertical_scrollbar = new QScrollBar(Qt::Vertical, this); + horizontal_scrollbar = new QScrollBar(Qt::Horizontal, this); + vertical_scrollbar = new QScrollBar(Qt::Vertical, this); - horizontal_scrollbar->setVisible(false); - vertical_scrollbar->setVisible(false); + horizontal_scrollbar->setVisible(false); + vertical_scrollbar->setVisible(false); - horizontal_scrollbar->setSingleStep(20); - vertical_scrollbar->setSingleStep(20); + horizontal_scrollbar->setSingleStep(20); + vertical_scrollbar->setSingleStep(20); - child = new ViewerWidget(this); - child->container = this; + child = new ViewerWidget(this); + child->container = this; - connect(horizontal_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed())); - connect(vertical_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed())); + connect(horizontal_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed())); + connect(vertical_scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scroll_changed())); } ViewerContainer::~ViewerContainer() {} void ViewerContainer::dragScrollPress(const QPoint &p) { - drag_start_x = p.x(); - drag_start_y = p.y(); + drag_start_x = p.x(); + drag_start_y = p.y(); - horiz_start = horizontal_scrollbar->value(); - vert_start = vertical_scrollbar->value(); + horiz_start = horizontal_scrollbar->value(); + vert_start = vertical_scrollbar->value(); } void ViewerContainer::dragScrollMove(const QPoint &p) { - int this_x = p.x(); - int this_y = p.y(); + int this_x = p.x(); + int this_y = p.y(); - horizontal_scrollbar->setValue(horiz_start + (drag_start_x-this_x)); - vertical_scrollbar->setValue(vert_start + (drag_start_y-this_y)); + horizontal_scrollbar->setValue(horiz_start + (drag_start_x-this_x)); + vertical_scrollbar->setValue(vert_start + (drag_start_y-this_y)); } void ViewerContainer::parseWheelEvent(QWheelEvent *event) { - if (event->modifiers() & Qt::AltModifier) { - QApplication::sendEvent(horizontal_scrollbar, event); - } else { - QApplication::sendEvent(vertical_scrollbar, event); - } + if (event->modifiers() & Qt::AltModifier) { + QApplication::sendEvent(horizontal_scrollbar, event); + } else { + QApplication::sendEvent(vertical_scrollbar, event); + } } void ViewerContainer::adjust() { - if (viewer->seq != nullptr) { - if (child->waveform) { - child->move(0, 0); - child->resize(size()); - } else { - horizontal_scrollbar->setVisible(false); - vertical_scrollbar->setVisible(false); + if (viewer->seq != nullptr) { + if (child->waveform) { + child->move(0, 0); + child->resize(size()); + } else { + horizontal_scrollbar->setVisible(false); + vertical_scrollbar->setVisible(false); - int zoomed_width = qRound(double(viewer->seq->width)*zoom); + int zoomed_width = qRound(double(viewer->seq->width)*zoom); int zoomed_height = qRound(double(viewer->seq->height)*zoom); if (fit || zoomed_width > width() || zoomed_height > height()) { @@ -147,28 +147,28 @@ void ViewerContainer::adjust() { child->move(zoomed_x, zoomed_y); child->resize(zoomed_width, zoomed_height); } - } - } + } + } } void ViewerContainer::adjust_scrollbars() { - horizontal_scrollbar->move(0, height()-horizontal_scrollbar->height()); - horizontal_scrollbar->setFixedWidth(qMax(0, width()-vertical_scrollbar->width())); - horizontal_scrollbar->setPageStep(width()); + horizontal_scrollbar->move(0, height()-horizontal_scrollbar->height()); + horizontal_scrollbar->setFixedWidth(qMax(0, width()-vertical_scrollbar->width())); + horizontal_scrollbar->setPageStep(width()); - vertical_scrollbar->move(width() - vertical_scrollbar->width(), 0); - vertical_scrollbar->setFixedHeight(qMax(0, height()-horizontal_scrollbar->height())); - vertical_scrollbar->setPageStep(height()); + vertical_scrollbar->move(width() - vertical_scrollbar->width(), 0); + vertical_scrollbar->setFixedHeight(qMax(0, height()-horizontal_scrollbar->height())); + vertical_scrollbar->setPageStep(height()); } void ViewerContainer::resizeEvent(QResizeEvent *event) { - event->accept(); - adjust(); + event->accept(); + adjust(); } void ViewerContainer::scroll_changed() { - child->set_scroll( - double(horizontal_scrollbar->value())/double(horizontal_scrollbar->maximum()), - double(vertical_scrollbar->value())/double(vertical_scrollbar->maximum()) - ); + child->set_scroll( + double(horizontal_scrollbar->value())/double(horizontal_scrollbar->maximum()), + double(vertical_scrollbar->value())/double(vertical_scrollbar->maximum()) + ); } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 0db17dc66..50c40f832 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -46,11 +46,11 @@ extern "C" { #include "project/projectelements.h" #include "rendering/renderfunctions.h" #include "rendering/audio.h" -#include "io/config.h" -#include "debug.h" -#include "io/math.h" +#include "global/config.h" +#include "global/debug.h" +#include "global/math.h" #include "ui/collapsiblewidget.h" -#include "project/undo.h" +#include "undo/undo.h" #include "project/media.h" #include "ui/viewercontainer.h" #include "rendering/cacher.h" diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index adee06ff3..f01ae7063 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -30,9 +30,9 @@ #include #include -#include "project/clip.h" +#include "timeline/clip.h" #include "project/footage.h" -#include "project/effect.h" +#include "effects/effect.h" #include "ui/viewerwindow.h" #include "ui/viewercontainer.h" #include "rendering/renderthread.h" diff --git a/project/comboaction.cpp b/undo/comboaction.cpp similarity index 100% rename from project/comboaction.cpp rename to undo/comboaction.cpp diff --git a/project/comboaction.h b/undo/comboaction.h similarity index 100% rename from project/comboaction.h rename to undo/comboaction.h diff --git a/project/undo.cpp b/undo/undo.cpp similarity index 97% rename from project/undo.cpp rename to undo/undo.cpp index 1aa79eab3..e30228e9b 100644 --- a/project/undo.cpp +++ b/undo/undo.cpp @@ -25,28 +25,22 @@ #include #include -#include "project/clip.h" -#include "project/sequence.h" +#include "global/global.h" #include "panels/panels.h" #include "panels/project.h" #include "panels/effectcontrols.h" #include "panels/viewer.h" #include "panels/timeline.h" #include "ui/sourcetable.h" -#include "project/effect.h" -#include "project/transition.h" #include "project/footage.h" #include "rendering/renderfunctions.h" #include "rendering/cacher.h" -#include "io/previewgenerator.h" #include "ui/labelslider.h" #include "ui/viewerwidget.h" -#include "project/marker.h" -#include "mainwindow.h" -#include "io/clipboard.h" #include "project/media.h" -#include "debug.h" -#include "oliveglobal.h" +#include "project/clipboard.h" +#include "project/previewgenerator.h" +#include "ui/mainwindow.h" QUndoStack olive::UndoStack; @@ -598,9 +592,10 @@ void MediaRename::doRedo() { item->set_name(to); } -KeyframeDelete::KeyframeDelete(EffectField *ifield, int iindex) { - field = ifield; - index = iindex; +KeyframeDelete::KeyframeDelete(EffectField *ifield, int iindex) : + field(ifield), + index(iindex) +{ } void KeyframeDelete::doUndo() { @@ -1066,24 +1061,24 @@ void SetLong::doRedo() { *p = newval; } -KeyframeFieldSet::KeyframeFieldSet(EffectField *ifield, int ii) { - field = ifield; - index = ii; - key = ifield->keyframes.at(ii); - done = true; +KeyframeAdd::KeyframeAdd(EffectField *ifield, int ii) : + field(ifield), + index(ii), + key(ifield->keyframes.at(ii)), + done(true) +{ } -void KeyframeFieldSet::doUndo() { +void KeyframeAdd::doUndo() { field->keyframes.removeAt(index); - done = false; } -void KeyframeFieldSet::doRedo() { +void KeyframeAdd::doRedo() { if (!done) { field->keyframes.insert(index, key); + done = true; } - done = true; } SetIsKeyframing::SetIsKeyframing(EffectRow *irow, bool ib) { diff --git a/project/undo.h b/undo/undo.h similarity index 98% rename from project/undo.h rename to undo/undo.h index 62f53a50c..4327839f2 100644 --- a/project/undo.h +++ b/undo/undo.h @@ -21,13 +21,6 @@ #ifndef UNDO_H #define UNDO_H -#include "project/projectelements.h" -#include "project/selection.h" -#include "project/effectfields/effectfield.h" - -#include "ui/labelslider.h" -#include "ui/sourcetable.h" - #include #include #include @@ -35,6 +28,16 @@ #include #include +#include "project/projectelements.h" +#include "timeline/selection.h" +#include "timeline/clip.h" +#include "timeline/sequence.h" +#include "effects/transition.h" +#include "effects/effectfield.h" + +#include "ui/labelslider.h" +#include "ui/sourcetable.h" + namespace olive { extern QUndoStack UndoStack; } @@ -319,11 +322,9 @@ private: EffectKeyframe deleted_key; }; -// a more modern version of the above, could probably replace it -// assumes the keyframe already exists -class KeyframeFieldSet : public OliveAction { +class KeyframeAdd : public OliveAction { public: - KeyframeFieldSet(EffectField* ifield, int ii); + KeyframeAdd(EffectField* ifield, int ii); virtual void doUndo() override; virtual void doRedo() override; private: From 654c6f32c644b97435e59d6ea9ac619f0f5934ee Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 19:43:28 +1100 Subject: [PATCH 22/56] reimplemented updating UI from effect fields --- effects/fields/colorfield.cpp | 7 +++++++ effects/fields/colorfield.h | 1 + effects/fields/combofield.cpp | 20 ++++++++++++++++++++ effects/fields/combofield.h | 1 + effects/fields/fontfield.cpp | 21 +++++++++++++++++++++ effects/fields/fontfield.h | 4 +++- effects/fields/stringfield.cpp | 5 +++++ effects/fields/stringfield.h | 1 + effects/internal/solideffect.cpp | 2 +- 9 files changed, 60 insertions(+), 2 deletions(-) diff --git a/effects/fields/colorfield.cpp b/effects/fields/colorfield.cpp index 865505dd2..909c177d1 100644 --- a/effects/fields/colorfield.cpp +++ b/effects/fields/colorfield.cpp @@ -23,6 +23,13 @@ QWidget *ColorField::CreateWidget() return cb; } +void ColorField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + ColorButton* cb = static_cast(widget); + + cb->set_color(GetColorAt(timecode)); +} + QVariant ColorField::ConvertStringToValue(const QString &s) { return QColor(s); diff --git a/effects/fields/colorfield.h b/effects/fields/colorfield.h index 7c6d60216..9ff0b03c4 100644 --- a/effects/fields/colorfield.h +++ b/effects/fields/colorfield.h @@ -12,6 +12,7 @@ public: QColor GetColorAt(double timecode); virtual QWidget* CreateWidget() override; + virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; virtual QVariant ConvertStringToValue(const QString& s) override; virtual QString ConvertValueToString(const QVariant& v) override; diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp index 2058e9661..7b25645f4 100644 --- a/effects/fields/combofield.cpp +++ b/effects/fields/combofield.cpp @@ -1,5 +1,7 @@ #include "combofield.h" +#include + #include "ui/comboboxex.h" ComboField::ComboField(EffectRow* parent, const QString& id) : @@ -32,6 +34,24 @@ QWidget *ComboField::CreateWidget() return cb; } +void ComboField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + QVariant data = GetValueAt(timecode); + + ComboBoxEx* cb = static_cast(widget); + + for (int i=0;iblockSignals(true); + cb->setCurrentIndex(i); + cb->blockSignals(false); + return; + } + } + + qWarning() << "Failed to set ComboField value from data"; +} + void ComboField::UpdateFromWidget(int index) { SetValueAt(Now(), items_.at(index).data); diff --git a/effects/fields/combofield.h b/effects/fields/combofield.h index bdf5a9972..97fe2efd7 100644 --- a/effects/fields/combofield.h +++ b/effects/fields/combofield.h @@ -17,6 +17,7 @@ public: void AddItem(const QString& text, const QVariant& data); virtual QWidget *CreateWidget() override; + virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; signals: void IndexChanged(int i); diff --git a/effects/fields/fontfield.cpp b/effects/fields/fontfield.cpp index b647dd17e..9c7343225 100644 --- a/effects/fields/fontfield.cpp +++ b/effects/fields/fontfield.cpp @@ -1,9 +1,12 @@ #include "fontfield.h" #include +#include #include "ui/comboboxex.h" +// NOTE/TODO: This shares a lot of similarity with ComboField, and could probably be a derived class of it + FontField::FontField(EffectRow* parent, const QString &id) : EffectField(parent, id, EFFECT_FIELD_FONT) { @@ -31,6 +34,24 @@ QWidget *FontField::CreateWidget() return fcb; } +void FontField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + QVariant data = GetValueAt(timecode); + + ComboBoxEx* cb = static_cast(widget); + + for (int i=0;iblockSignals(true); + cb->setCurrentIndex(i); + cb->blockSignals(false); + return; + } + } + + qWarning() << "Failed to set FontField value from data"; +} + void FontField::UpdateFromWidget(const QString& s) { SetValueAt(Now(), s); diff --git a/effects/fields/fontfield.h b/effects/fields/fontfield.h index ddd2b05be..f8b095d2b 100644 --- a/effects/fields/fontfield.h +++ b/effects/fields/fontfield.h @@ -1,7 +1,7 @@ #ifndef FONTFIELD_H #define FONTFIELD_H -#include "../effectfield.h" +#include "combofield.h" class FontField : public EffectField { Q_OBJECT @@ -11,6 +11,8 @@ public: QString GetFontAt(double timecode); virtual QWidget *CreateWidget() override; + virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; + private: QStringList font_list; private slots: diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index b2f38a246..b885ef035 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -34,6 +34,11 @@ QWidget *StringField::CreateWidget() return text_edit; } +void StringField::UpdateWidgetValue(QWidget *widget, double timecode) +{ + static_cast(widget)->setHtml(GetValueAt(timecode).toString()); +} + void StringField::UpdateFromWidget(const QString &s) { SetValueAt(Now(), s); diff --git a/effects/fields/stringfield.h b/effects/fields/stringfield.h index 4643f7bd6..969ce52af 100644 --- a/effects/fields/stringfield.h +++ b/effects/fields/stringfield.h @@ -12,6 +12,7 @@ public: QString GetStringAt(double timecode); virtual QWidget *CreateWidget() override; + virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; private slots: void UpdateFromWidget(const QString& b); }; diff --git a/effects/internal/solideffect.cpp b/effects/internal/solideffect.cpp index 95b01cb2d..7dd6c5cc3 100644 --- a/effects/internal/solideffect.cpp +++ b/effects/internal/solideffect.cpp @@ -49,7 +49,7 @@ SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : EffectRow* opacity_row = new EffectRow(this, tr("Opacity")); opacity_field = new DoubleField(opacity_row, "opacity"); opacity_field->SetMinimum(0); - opacity_field->SetDefault(0); + opacity_field->SetDefault(100); opacity_field->SetMaximum(100); EffectRow* solid_color_row = new EffectRow(this, tr("Color")); From c634070368788793e650deddf898483f77440459 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 21:34:23 +1100 Subject: [PATCH 23/56] added styling options and rearranged preferences --- dialogs/preferencesdialog.cpp | 125 ++++++++++++++++++++++------------ dialogs/preferencesdialog.h | 1 + effects/effect.cpp | 2 +- effects/effectrow.cpp | 5 +- global/config.cpp | 7 +- global/config.h | 9 +++ olive.pro | 6 +- ui/icons.cpp | 18 ++++- ui/labelslider.cpp | 9 ++- ui/mainwindow.cpp | 77 ++++++++++++--------- ui/mainwindow.h | 12 +++- ui/styling.cpp | 24 +++++++ ui/styling.h | 67 ++++++++++++++++++ ui/timelineheader.cpp | 5 +- 14 files changed, 282 insertions(+), 85 deletions(-) create mode 100644 ui/styling.cpp create mode 100644 ui/styling.h diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index 1ac93c362..e5115e906 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -194,7 +194,8 @@ void PreferencesDialog::save() { // Check if any settings will require a restart of Olive if (olive::CurrentConfig.use_software_fallback != use_software_fallbacks_checkbox->isChecked() || olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() - || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) { + || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value() + || olive::CurrentConfig.style != static_cast(ui_style->currentData().toInt())) { // any changes to these settings will require a restart - ask the user if we should do one now or later @@ -234,8 +235,10 @@ void PreferencesDialog::save() { } // save settings from UI to backend - olive::CurrentConfig.css_path = custom_css_fn->text(); - olive::MainWindow->load_css_from_file(olive::CurrentConfig.css_path); + if (olive::CurrentConfig.css_path != custom_css_fn->text()) { + olive::CurrentConfig.css_path = custom_css_fn->text(); + olive::MainWindow->Restyle(); + } olive::CurrentConfig.recording_mode = recordingComboBox->currentIndex() + 1; olive::CurrentConfig.img_seq_formats = imgSeqFormatEdit->text(); @@ -254,6 +257,9 @@ void PreferencesDialog::save() { olive::CurrentConfig.use_software_fallback = use_software_fallbacks_checkbox->isChecked(); olive::CurrentConfig.language_file = language_combobox->currentData().toString(); + olive::CurrentConfig.style = static_cast(ui_style->currentData().toInt()); + + // Check if the thumbnail or waveform icon if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value() || olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) { // we're changing the size of thumbnails and waveforms, so let's delete them and regenerate them next start @@ -500,19 +506,6 @@ void PreferencesDialog::setup_ui() { row++; - // General -> Custom CSS - general_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0); - - custom_css_fn = new QLineEdit(general_tab); - custom_css_fn->setText(olive::CurrentConfig.css_path); - general_layout->addWidget(custom_css_fn, row, 1, 1, 3); - - QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); - connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file())); - general_layout->addWidget(custom_css_browse, row, 4); - - row++; - // General -> Image Sequence Formats general_layout->addWidget(new QLabel(tr("Image sequence formats:"), this), row, 0); @@ -522,26 +515,6 @@ void PreferencesDialog::setup_ui() { row++; - // General -> Audio Recording - general_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0); - - recordingComboBox = new QComboBox(general_tab); - recordingComboBox->addItem(tr("Mono")); - recordingComboBox->addItem(tr("Stereo")); - general_layout->addWidget(recordingComboBox, row, 1, 1, 4); - - row++; - - // General -> Effect Textbox Lines - general_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0); - - effect_textbox_lines_field = new QSpinBox(general_tab); - effect_textbox_lines_field->setMinimum(1); - effect_textbox_lines_field->setValue(olive::CurrentConfig.effect_textbox_lines); - general_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 4); - - row++; - // General -> Thumbnail and Waveform Resolution general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0); @@ -583,6 +556,50 @@ void PreferencesDialog::setup_ui() { add_default_effects_to_clips->setChecked(olive::CurrentConfig.add_default_effects_to_clips); behavior_tab_layout->addWidget(add_default_effects_to_clips); + // Appearance + QWidget* appearance_tab = new QWidget(this); + tabWidget->addTab(appearance_tab, tr("Appearance")); + + row = 0; + + QGridLayout* appearance_layout = new QGridLayout(appearance_tab); + + // Appearance -> Theme + appearance_layout->addWidget(new QLabel(tr("Theme")), row, 0); + + ui_style = new QComboBox(); + ui_style->addItem(tr("Olive Dark (Default)"), olive::styling::kOliveDefaultDark); + ui_style->addItem(tr("Olive Light"), olive::styling::kOliveDefaultLight); + ui_style->addItem(tr("Native"), olive::styling::kNativeDarkIcons); + ui_style->addItem(tr("Native (Light Icons)"), olive::styling::kNativeLightIcons); + ui_style->setCurrentIndex(olive::CurrentConfig.style); + appearance_layout->addWidget(ui_style, row, 1, 1, 2); + + row++; + + // Appearance -> Custom CSS + appearance_layout->addWidget(new QLabel(tr("Custom CSS:"), this), row, 0); + + custom_css_fn = new QLineEdit(general_tab); + custom_css_fn->setText(olive::CurrentConfig.css_path); + appearance_layout->addWidget(custom_css_fn, row, 1); + + QPushButton* custom_css_browse = new QPushButton(tr("Browse"), general_tab); + connect(custom_css_browse, SIGNAL(clicked(bool)), this, SLOT(browse_css_file())); + appearance_layout->addWidget(custom_css_browse, row, 2); + + row++; + + // Appearance -> Effect Textbox Lines + appearance_layout->addWidget(new QLabel(tr("Effect Textbox Lines:"), this), row, 0); + + effect_textbox_lines_field = new QSpinBox(general_tab); + effect_textbox_lines_field->setMinimum(1); + effect_textbox_lines_field->setValue(olive::CurrentConfig.effect_textbox_lines); + appearance_layout->addWidget(effect_textbox_lines_field, row, 1, 1, 2); + + row++; + // Playback QWidget* playback_tab = new QWidget(this); QVBoxLayout* playback_tab_layout = new QVBoxLayout(playback_tab); @@ -630,7 +647,11 @@ void PreferencesDialog::setup_ui() { QGridLayout* audio_tab_layout = new QGridLayout(audio_tab); - audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), 0, 0); + row = 0; + + // Audio -> Output Device + + audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0); audio_output_devices = new QComboBox(); audio_output_devices->addItem(tr("Default"), ""); @@ -647,9 +668,13 @@ void PreferencesDialog::setup_ui() { } } - audio_tab_layout->addWidget(audio_output_devices, 0, 1); + audio_tab_layout->addWidget(audio_output_devices, row, 1); - audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), 1, 0); + row++; + + // Audio -> Input Device + + audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0); audio_input_devices = new QComboBox(); audio_input_devices->addItem(tr("Default"), ""); @@ -666,9 +691,13 @@ void PreferencesDialog::setup_ui() { } } - audio_tab_layout->addWidget(audio_input_devices, 1, 1); + audio_tab_layout->addWidget(audio_input_devices, row, 1); - audio_tab_layout->addWidget(new QLabel(tr("Sample Rate:")), 2, 0); + row++; + + // Audio -> Sample Rate + + audio_tab_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); audio_sample_rate = new QComboBox(); combobox_audio_sample_rates(audio_sample_rate); @@ -679,7 +708,19 @@ void PreferencesDialog::setup_ui() { } } - audio_tab_layout->addWidget(audio_sample_rate, 2, 1); + audio_tab_layout->addWidget(audio_sample_rate, row, 1); + + row++; + + // Audio -> Audio Recording + audio_tab_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0); + + recordingComboBox = new QComboBox(general_tab); + recordingComboBox->addItem(tr("Mono")); + recordingComboBox->addItem(tr("Stereo")); + audio_tab_layout->addWidget(recordingComboBox, row, 1); + + row++; tabWidget->addTab(audio_tab, tr("Audio")); diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index 03d7bd4e5..e192a9a63 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -93,6 +93,7 @@ private: QSpinBox* thumbnail_res_spinbox; QSpinBox* waveform_res_spinbox; QCheckBox* add_default_effects_to_clips; + QComboBox* ui_style; QVector key_shortcut_actions; QVector key_shortcut_items; diff --git a/effects/effect.cpp b/effects/effect.cpp index 799aa3538..dec9b4d38 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -595,7 +595,7 @@ void Effect::save(QXmlStreamWriter& stream) { for (int j=0;jFieldCount();j++) { EffectField* field = row->Field(j); - if (field->id().isEmpty()) { + if (!field->id().isEmpty()) { stream.writeStartElement("field"); // field stream.writeAttribute("id", field->id()); for (int k=0;kkeyframes.size();k++) { diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index 16cfde39d..3821c08a0 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -85,6 +85,8 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { olive::UndoStack.push(ca); + update_ui(false); + } else { // Confirm with the user whether they really want to disable keyframing @@ -105,7 +107,8 @@ void EffectRow::SetKeyframingEnabled(bool enabled) { ca->append(new SetIsKeyframing(this, false)); olive::UndoStack.push(ca); - panel_effect_controls->update_keyframes(); + + update_ui(false); } else { diff --git a/global/config.cpp b/global/config.cpp index 5b09d877b..53b43e42a 100644 --- a/global/config.cpp +++ b/global/config.cpp @@ -71,7 +71,8 @@ Config::Config() waveform_resolution(64), thumbnail_resolution(120), add_default_effects_to_clips(true), - invert_timeline_scroll_axes(true) + invert_timeline_scroll_axes(true), + style(olive::styling::kOliveDefaultDark) {} void Config::load(QString path) { @@ -211,6 +212,9 @@ void Config::load(QString path) { } else if (stream.name() == "AddDefaultEffectsToClips") { stream.readNext(); add_default_effects_to_clips = (stream.text() == "1"); + } else if (stream.name() == "Style") { + stream.readNext(); + style = static_cast(stream.text().toInt()); } } } @@ -278,6 +282,7 @@ void Config::save(QString path) { stream.writeTextElement("ThumbnailResolution", QString::number(thumbnail_resolution)); stream.writeTextElement("WaveformResolution", QString::number(waveform_resolution)); stream.writeTextElement("AddDefaultEffectsToClips", QString::number(add_default_effects_to_clips)); + stream.writeTextElement("Style", QString::number(style)); stream.writeEndElement(); // configuration stream.writeEndDocument(); // doc diff --git a/global/config.h b/global/config.h index a83eb30d7..3b768e31e 100644 --- a/global/config.h +++ b/global/config.h @@ -23,6 +23,8 @@ #include +#include "ui/styling.h" + namespace olive { /** * @brief Version identifier for saved projects @@ -517,6 +519,13 @@ struct Config { */ bool invert_timeline_scroll_axes; + /** + * @brief Style to use when theming Olive. + * + * Set to a member of olive::styling::Style. + */ + olive::styling::Style style; + /** * @brief Load config from file * diff --git a/olive.pro b/olive.pro index 252f51051..f559cbf16 100644 --- a/olive.pro +++ b/olive.pro @@ -170,7 +170,8 @@ SOURCES += \ effects/fields/labelfield.cpp \ effects/fields/buttonfield.cpp \ ui/effectui.cpp \ - effects/transition.cpp + effects/transition.cpp \ + ui/styling.cpp HEADERS += \ ui/mainwindow.h \ @@ -294,7 +295,8 @@ HEADERS += \ effects/fields/buttonfield.h \ effects/fields/colorfield.h \ effects/fields/combofield.h \ - effects/transition.h + effects/transition.h \ + ui/styling.h FORMS += diff --git a/ui/icons.cpp b/ui/icons.cpp index 19dda5aeb..0e3eff232 100644 --- a/ui/icons.cpp +++ b/ui/icons.cpp @@ -1,6 +1,7 @@ #include "icons.h" -#include "oliveglobal.h" +#include "global/global.h" +#include "global/config.h" QIcon olive::icon::LeftArrow; QIcon olive::icon::RightArrow; @@ -27,14 +28,27 @@ QIcon olive::icon::CreateIconFromSVG(const QString &path) { QIcon icon; + QPainter p; + + // Draw the icon as a solid color QPixmap normal(path); + + if (olive::styling::UseDarkIcons()) { + p.begin(&normal); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(normal.rect(), QColor(32, 32, 32)); + p.end(); + } + icon.addPixmap(normal, QIcon::Normal, QIcon::On); + // Create semi-transparent disabled icon QPixmap disabled(normal.size()); disabled.fill(Qt::transparent); // draw semi-transparent version of icon for the disabled variant - QPainter p(&disabled); + p.begin(&disabled); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setOpacity(0.5); p.drawPixmap(0, 0, normal); p.end(); diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 614c8b556..94751124e 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -25,6 +25,7 @@ #include "global/config.h" #include "global/math.h" #include "global/debug.h" +#include "ui/styling.h" #include #include @@ -119,7 +120,13 @@ QString LabelSlider::ValueToString() { } void LabelSlider::SetColor(QString c) { - if (c.isEmpty()) c = "#ffc000"; + if (c.isEmpty()) { + if (olive::styling::UseDarkIcons()) { + c = "#0080ff"; + } else { + c = "#ffc000"; + } + } setStyleSheet("QLabel{color:" + c + ";text-decoration:underline;}QLabel:disabled{color:#808080;}"); } diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 9c14f7da4..ca7b47eec 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -194,7 +194,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), first_show(true) { - olive::icon::Initialize(); olive::cursor::Initialize(); open_debug_file(); @@ -203,29 +202,6 @@ MainWindow::MainWindow(QWidget *parent) : olive::MainWindow = this; - // set up style? - - qApp->setStyle(QStyleFactory::create("Fusion")); - setStyleSheet(DEFAULT_CSS); - - QPalette darkPalette; - darkPalette.setColor(QPalette::Window, QColor(53,53,53)); - darkPalette.setColor(QPalette::WindowText, Qt::white); - darkPalette.setColor(QPalette::Base, QColor(25,25,25)); - darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); - darkPalette.setColor(QPalette::ToolTipBase, QColor(25,25,25)); - darkPalette.setColor(QPalette::ToolTipText, Qt::white); - darkPalette.setColor(QPalette::Text, Qt::white); - darkPalette.setColor(QPalette::Button, QColor(53,53,53)); - darkPalette.setColor(QPalette::ButtonText, Qt::white); darkPalette.setColor(QPalette::BrightText, Qt::red); - darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); - darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::HighlightedText, Qt::black); - - qApp->setPalette(darkPalette); - - // end style QWidget* centralWidget = new QWidget(this); centralWidget->setMaximumSize(QSize(0, 0)); setCentralWidget(centralWidget); @@ -296,13 +272,13 @@ MainWindow::MainWindow(QWidget *parent) : QString config_fn = config_dir.filePath("config.xml"); if (QFileInfo::exists(config_fn)) { olive::CurrentConfig.load(config_fn); - - if (!olive::CurrentConfig.css_path.isEmpty()) { - load_css_from_file(olive::CurrentConfig.css_path); - } } } + Restyle(); + + olive::icon::Initialize(); + alloc_panels(this); // populate menu bars @@ -413,14 +389,53 @@ void MainWindow::save_shortcuts(const QString& fn) { } } -void MainWindow::load_css_from_file(const QString &fn) { +bool MainWindow::load_css_from_file(const QString &fn) { QFile css_file(fn); if (css_file.exists() && css_file.open(QFile::ReadOnly)) { setStyleSheet(css_file.readAll()); css_file.close(); + return true; + } + return false; +} + +void MainWindow::Restyle() +{ + // Set up UI style + if (olive::styling::UseNativeUI()) { + qApp->setStyle(QStyleFactory::create("")); } else { - // set default stylesheet - setStyleSheet(DEFAULT_CSS); + qApp->setStyle(QStyleFactory::create("Fusion")); + + // Set up whether to load custom CSS or default CSS+palette + if (!olive::CurrentConfig.css_path.isEmpty() + && load_css_from_file(olive::CurrentConfig.css_path)) { + + setPalette(QPalette()); + + } else { + + // set default palette + QPalette darkPalette; + darkPalette.setColor(QPalette::Window, QColor(53,53,53)); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, QColor(25,25,25)); + darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); + darkPalette.setColor(QPalette::ToolTipBase, QColor(25,25,25)); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, QColor(53,53,53)); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(128, 128, 128)); + darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); + darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + darkPalette.setColor(QPalette::HighlightedText, Qt::black); + qApp->setPalette(darkPalette); + + // set default CSS + setStyleSheet(DEFAULT_CSS); + } } } diff --git a/ui/mainwindow.h b/ui/mainwindow.h index 2aad2a65f..e06987228 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -73,8 +73,17 @@ public: * @param fn * * URL to load the CSS file from. + * + * @return + * + * **TRUE** if CSS was successfully loaded. */ - void load_css_from_file(const QString& fn); + bool load_css_from_file(const QString& fn); + + /** + * @brief Set application's QStyle based on values from Config + */ + void Restyle(); public slots: /** @@ -248,7 +257,6 @@ private: QAction* ripple_delete_inout_point_; QAction* setedit_marker_; - // view menu actions QMenu* view_menu; QAction* zoom_in_; diff --git a/ui/styling.cpp b/ui/styling.cpp new file mode 100644 index 000000000..2c890a3ef --- /dev/null +++ b/ui/styling.cpp @@ -0,0 +1,24 @@ +#include "styling.h" + +#include "global/config.h" + +bool olive::styling::UseDarkIcons() +{ + return olive::CurrentConfig.style == kOliveDefaultLight || olive::CurrentConfig.style == kNativeDarkIcons; +} + +QColor olive::styling::GetIconColor() +{ + if (UseDarkIcons()) { + return Qt::black; + } else { + return Qt::white; + } +} + + + +bool olive::styling::UseNativeUI() +{ + return olive::CurrentConfig.style == kNativeLightIcons || olive::CurrentConfig.style == kNativeDarkIcons; +} diff --git a/ui/styling.h b/ui/styling.h new file mode 100644 index 000000000..c8a1b7343 --- /dev/null +++ b/ui/styling.h @@ -0,0 +1,67 @@ +#ifndef STYLING_H +#define STYLING_H + +#include + +namespace olive { + namespace styling { + + /** + * @brief Officially supported styles to use in Olive + */ + enum Style { + /** + Qt Fusion-based cross-platform UI. The default styling of Olive. Can also be heavily customized with a CSS + file. + */ + kOliveDefaultDark, + + /** + Qt Fusion-based cross-platform UI. The default styling of Olive. Can also be heavily customized with a CSS + file. This will use the + */ + kOliveDefaultLight, + + /** + Use current OS's native styling (or at least Qt's default). Most UIs use a light theming, so this will + automatically implement dark icons/UI elements. + */ + kNativeDarkIcons, + + /** + Use current OS's native styling (or at least Qt's default). Most UIs use a light theming, but in case one + doesn't, this option will provide light icons for use with a dark theme. + */ + kNativeLightIcons + }; + + /** + * @brief Return whether to use dark icons or light icons + * @return + * + * **TRUE** if icons should be dark. + */ + bool UseDarkIcons(); + + /** + * @brief Return whether to use native UI or Fusion + * @return + * + * **TRUE** if UI should use native styling + */ + bool UseNativeUI(); + + /** + * @brief Return the current icon color based on Config::use_dark_icons. + * + * Also used by some other UI elements like the lines and text on the TimelineHeader + * + * @return + * + * Either white or black depending on Config::use_dark_icons + */ + QColor GetIconColor(); + } +} + +#endif // STYLING_H diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 510132704..de9e71902 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -28,6 +28,7 @@ #include "project/media.h" #include "panels/viewer.h" #include "global/config.h" +#include "global/global.h" #include "ui/menuhelper.h" #include "global/debug.h" @@ -393,7 +394,7 @@ void TimelineHeader::paintEvent(QPaintEvent*) { if (lineX > lastLineX+LINE_MIN_PADDING) { if (draw_text) { - p.setPen(Qt::white); + p.setPen(olive::styling::GetIconColor()); p.drawText(QRect(text_x, 0, fullTextWidth, yoff), timecode); } @@ -419,7 +420,7 @@ void TimelineHeader::paintEvent(QPaintEvent*) { in_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_in : viewer->seq->workarea_in)); int out_x = getHeaderScreenPointFromFrame((resizing_workarea ? temp_workarea_out : viewer->seq->workarea_out)); p.fillRect(QRect(in_x, 0, out_x-in_x, height()), QColor(0, 192, 255, 128)); - p.setPen(Qt::white); + p.setPen(olive::styling::GetIconColor()); p.drawLine(in_x, 0, in_x, height()); p.drawLine(out_x, 0, out_x, height()); } From 06ed5ea05d926d67f3645226faf0d63f7e811363 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 21:34:44 +1100 Subject: [PATCH 24/56] fixed crash pressing space on null sequence --- panels/viewer.cpp | 4 ++++ ui/viewerwidget.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 67c1f2c35..e31e0cbea 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -376,6 +376,10 @@ void Viewer::decrease_speed() { } void Viewer::play(bool in_to_out) { + if (seq == nullptr) { + return; + } + if (panel_sequence_viewer->playing) panel_sequence_viewer->pause(); if (panel_footage_viewer->playing) panel_footage_viewer->pause(); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 50c40f832..5901098b0 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -574,7 +574,6 @@ void ViewerWidget::paintGL() { glBegin(GL_QUADS); - // double ar_diff = (double(viewer->seq->width)/double(viewer->seq->height)/(double(width())/double(height()))); double zoom_factor = container->zoom/(double(width())/double(viewer->seq->width)); double zoom_size = (zoom_factor*2.0) - 2.0; double zoom_left = -zoom_size*x_scroll - 1.0; From 933cbb0304f2a64f307ab00cc2e95613e845a35e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 22:34:26 +1100 Subject: [PATCH 25/56] reimplemented dragging all field types --- dialogs/aboutdialog.cpp | 2 +- dialogs/actionsearch.cpp | 174 ++++++++++++++++----------------- dialogs/debugdialog.cpp | 12 +-- effects/effect.h | 1 - effects/effectfield.h | 1 + effects/effectgizmo.cpp | 4 +- effects/effectrow.cpp | 34 ++++++- effects/fields/boolfield.cpp | 5 + effects/fields/colorfield.cpp | 5 + effects/fields/combofield.cpp | 5 + effects/fields/doublefield.cpp | 18 +++- effects/fields/doublefield.h | 2 + effects/fields/filefield.cpp | 5 + effects/fields/fontfield.cpp | 5 + effects/fields/stringfield.cpp | 5 + ui/checkboxex.cpp | 6 +- ui/collapsiblewidget.cpp | 2 +- ui/colorbutton.cpp | 13 --- ui/colorbutton.h | 11 --- ui/effectui.cpp | 2 + ui/icons.cpp | 2 + ui/keyframedrawing.cpp | 4 +- ui/keyframenavigator.cpp | 1 + ui/keyframenavigator.h | 1 + ui/resizablescrollbar.cpp | 2 +- ui/sourcetable.h | 20 ++-- undo/undo.cpp | 42 +++++--- undo/undo.h | 59 +++++++---- 28 files changed, 265 insertions(+), 178 deletions(-) diff --git a/dialogs/aboutdialog.cpp b/dialogs/aboutdialog.cpp index 3e5969075..711c11e73 100644 --- a/dialogs/aboutdialog.cpp +++ b/dialogs/aboutdialog.cpp @@ -24,7 +24,7 @@ #include #include -#include "oliveglobal.h" +#include "global/global.h" AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) diff --git a/dialogs/actionsearch.cpp b/dialogs/actionsearch.cpp index a21a2ef3d..c112061dd 100644 --- a/dialogs/actionsearch.cpp +++ b/dialogs/actionsearch.cpp @@ -25,123 +25,123 @@ #include #include -#include "mainwindow.h" +#include "ui/mainwindow.h" ActionSearch::ActionSearch(QWidget *parent) : - QDialog(parent) + QDialog(parent) { - setObjectName("ASDiag"); - setStyleSheet("#ASDiag{border: 2px solid #808080;}"); + setObjectName("ASDiag"); + setStyleSheet("#ASDiag{border: 2px solid #808080;}"); - resize(parent->width()/3, parent->height()/3); + resize(parent->width()/3, parent->height()/3); - setWindowFlags(Qt::Popup); + setWindowFlags(Qt::Popup); - QVBoxLayout* layout = new QVBoxLayout(this); + QVBoxLayout* layout = new QVBoxLayout(this); - ActionSearchEntry* entry_field = new ActionSearchEntry(this); - QFont entry_field_font = entry_field->font(); - entry_field_font.setPointSize(qRound(entry_field_font.pointSize()*1.2)); - entry_field->setFont(entry_field_font); - entry_field->setPlaceholderText(tr("Search for action...")); - connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &))); - connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action())); - connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up())); - connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down())); - layout->addWidget(entry_field); + ActionSearchEntry* entry_field = new ActionSearchEntry(this); + QFont entry_field_font = entry_field->font(); + entry_field_font.setPointSize(qRound(entry_field_font.pointSize()*1.2)); + entry_field->setFont(entry_field_font); + entry_field->setPlaceholderText(tr("Search for action...")); + connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &))); + connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action())); + connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up())); + connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down())); + layout->addWidget(entry_field); - list_widget = new ActionSearchList(this); - QFont list_widget_font = list_widget->font(); - list_widget_font.setPointSize(qRound(list_widget_font.pointSize()*1.2)); - list_widget->setFont(list_widget_font); - layout->addWidget(list_widget); - connect(list_widget, SIGNAL(dbl_click()), this, SLOT(perform_action())); + list_widget = new ActionSearchList(this); + QFont list_widget_font = list_widget->font(); + list_widget_font.setPointSize(qRound(list_widget_font.pointSize()*1.2)); + list_widget->setFont(list_widget_font); + layout->addWidget(list_widget); + connect(list_widget, SIGNAL(dbl_click()), this, SLOT(perform_action())); - entry_field->setFocus(); + entry_field->setFocus(); } void ActionSearch::search_update(const QString &s, const QString &p, QMenu *parent) { - if (parent == nullptr) { - list_widget->clear(); + if (parent == nullptr) { + list_widget->clear(); QList menus = olive::MainWindow->menuBar()->actions(); - for (int i=0;imenu(); - search_update(s, p, menu); - } - if (list_widget->count() > 0) - list_widget->item(0)->setSelected(true); - } else { - QString menu_text; - if (!p.isEmpty()) menu_text += p + " > "; - menu_text += parent->title().replace("&", ""); - QList actions = parent->actions(); - for (int i=0;iisSeparator()) { - if (a->menu() != nullptr) { - search_update(s, menu_text, a->menu()); - } else { - QString comp = a->text().replace("&", ""); - if (comp.contains(s, Qt::CaseInsensitive)) { - QListWidgetItem* item = new QListWidgetItem(QString("%1\n(%2)").arg(comp, menu_text), list_widget); - item->setData(Qt::UserRole+1, reinterpret_cast(a)); - list_widget->addItem(item); - } - } - } - } - } + for (int i=0;imenu(); + search_update(s, p, menu); + } + if (list_widget->count() > 0) + list_widget->item(0)->setSelected(true); + } else { + QString menu_text; + if (!p.isEmpty()) menu_text += p + " > "; + menu_text += parent->title().replace("&", ""); + QList actions = parent->actions(); + for (int i=0;iisSeparator()) { + if (a->menu() != nullptr) { + search_update(s, menu_text, a->menu()); + } else { + QString comp = a->text().replace("&", ""); + if (comp.contains(s, Qt::CaseInsensitive)) { + QListWidgetItem* item = new QListWidgetItem(QString("%1\n(%2)").arg(comp, menu_text), list_widget); + item->setData(Qt::UserRole+1, reinterpret_cast(a)); + list_widget->addItem(item); + } + } + } + } + } } void ActionSearch::perform_action() { - QList selected_items = list_widget->selectedItems(); - if (list_widget->count() > 0 && selected_items.size() > 0) { - QListWidgetItem* item = selected_items.at(0); - QAction* a = reinterpret_cast(item->data(Qt::UserRole+1).value()); - a->trigger(); - } - accept(); + QList selected_items = list_widget->selectedItems(); + if (list_widget->count() > 0 && selected_items.size() > 0) { + QListWidgetItem* item = selected_items.at(0); + QAction* a = reinterpret_cast(item->data(Qt::UserRole+1).value()); + a->trigger(); + } + accept(); } void ActionSearch::move_selection_up() { - int lim = list_widget->count(); - for (int i=1;iitem(i)->isSelected()) { - list_widget->item(i-1)->setSelected(true); - list_widget->scrollToItem(list_widget->item(i-1)); - break; - } - } + int lim = list_widget->count(); + for (int i=1;iitem(i)->isSelected()) { + list_widget->item(i-1)->setSelected(true); + list_widget->scrollToItem(list_widget->item(i-1)); + break; + } + } } void ActionSearch::move_selection_down() { - int lim = list_widget->count()-1; - for (int i=0;iitem(i)->isSelected()) { - list_widget->item(i+1)->setSelected(true); - list_widget->scrollToItem(list_widget->item(i+1)); - break; - } - } + int lim = list_widget->count()-1; + for (int i=0;iitem(i)->isSelected()) { + list_widget->item(i+1)->setSelected(true); + list_widget->scrollToItem(list_widget->item(i+1)); + break; + } + } } ActionSearchEntry::ActionSearchEntry(QWidget *parent) : QLineEdit(parent) {} void ActionSearchEntry::keyPressEvent(QKeyEvent * event) { - switch (event->key()) { - case Qt::Key_Up: - emit moveSelectionUp(); - break; - case Qt::Key_Down: - emit moveSelectionDown(); - break; - default: - QLineEdit::keyPressEvent(event); - } + switch (event->key()) { + case Qt::Key_Up: + emit moveSelectionUp(); + break; + case Qt::Key_Down: + emit moveSelectionDown(); + break; + default: + QLineEdit::keyPressEvent(event); + } } ActionSearchList::ActionSearchList(QWidget *parent) : QListWidget(parent) {} void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) { - emit dbl_click(); + emit dbl_click(); } diff --git a/dialogs/debugdialog.cpp b/dialogs/debugdialog.cpp index 33e8e29a2..6205d661a 100644 --- a/dialogs/debugdialog.cpp +++ b/dialogs/debugdialog.cpp @@ -25,15 +25,15 @@ #include #include -#include "debug.h" +#include "global/debug.h" DebugDialog* olive::DebugDialog = nullptr; DebugDialog::DebugDialog(QWidget *parent) : QDialog(parent) { - QVBoxLayout* layout = new QVBoxLayout(this); + QVBoxLayout* layout = new QVBoxLayout(this); - textEdit = new QTextEdit(this); - textEdit->setWordWrapMode(QTextOption::NoWrap); + textEdit = new QTextEdit(this); + textEdit->setWordWrapMode(QTextOption::NoWrap); layout->addWidget(textEdit); Retranslate(); @@ -45,7 +45,7 @@ void DebugDialog::Retranslate() } void DebugDialog::update_log() { - textEdit->setHtml(get_debug_str()); + textEdit->setHtml(get_debug_str()); textEdit->verticalScrollBar()->setValue(textEdit->verticalScrollBar()->maximum()); } @@ -59,5 +59,5 @@ void DebugDialog::changeEvent(QEvent *e) } void DebugDialog::showEvent(QShowEvent *) { - update_log(); + update_log(); } diff --git a/effects/effect.h b/effects/effect.h index e7c9ca99f..325406836 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -42,7 +42,6 @@ #include "ui/collapsiblewidget.h" #include "ui/checkboxex.h" -#include "effectfields.h" #include "effectrow.h" #include "effectgizmo.h" diff --git a/effects/effectfield.h b/effects/effectfield.h index f8f824896..a41566ce0 100644 --- a/effects/effectfield.h +++ b/effects/effectfield.h @@ -26,6 +26,7 @@ #include #include "effects/keyframe.h" +#include "undo/undo.h" class EffectRow; class ComboAction; diff --git a/effects/effectgizmo.cpp b/effects/effectgizmo.cpp index 9d3413708..c1449b657 100644 --- a/effects/effectgizmo.cpp +++ b/effects/effectgizmo.cpp @@ -21,8 +21,8 @@ #include "effectgizmo.h" #include "ui/labelslider.h" -#include "effectfields/doublefield.h" -#include "project/effect.h" +#include "effects/fields/doublefield.h" +#include "effects/effect.h" EffectGizmo::EffectGizmo(Effect *parent, int type) : QObject(parent), diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index 3821c08a0..bda3a1a76 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -183,8 +183,32 @@ void EffectRow::ToggleKeyframe() { } else { // If we DID find keyframes at this time, delete them - for (int i=0;iappend(new KeyframeDelete(key_fields.at(i), key_field_index.at(i))); + + QVector sorted_key_fields; + QVector sorted_key_field_index; + + // Since QVectors shift themselves when removing items, we need to sort these in reverse order + for (int i=0;iappend(new KeyframeDelete(sorted_key_fields.at(i), sorted_key_field_index.at(i))); } } @@ -215,7 +239,13 @@ void EffectRow::FocusRow() { void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) { for (int i=0;iSetValueAt(field->Now(), field->GetValueAt(field->Now())); + + kdc->SetNewKeyframes(); + ca->append(kdc); } panel_effect_controls->update_keyframes(); diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp index f7f4d70ac..9c23d9202 100644 --- a/effects/fields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -48,5 +48,10 @@ QString BoolField::ConvertValueToString(const QVariant &v) void BoolField::UpdateFromWidget(bool b) { + KeyframeDataChange* kdc = new KeyframeDataChange(this); + SetValueAt(Now(), b); + + kdc->SetNewKeyframes(); + olive::UndoStack.push(kdc); } diff --git a/effects/fields/colorfield.cpp b/effects/fields/colorfield.cpp index 909c177d1..a48c4b841 100644 --- a/effects/fields/colorfield.cpp +++ b/effects/fields/colorfield.cpp @@ -42,5 +42,10 @@ QString ColorField::ConvertValueToString(const QVariant &v) void ColorField::UpdateFromWidget(const QColor& c) { + KeyframeDataChange* kdc = new KeyframeDataChange(this); + SetValueAt(Now(), c); + + kdc->SetNewKeyframes(); + olive::UndoStack.push(kdc); } diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp index 7b25645f4..6b1a46e3f 100644 --- a/effects/fields/combofield.cpp +++ b/effects/fields/combofield.cpp @@ -54,5 +54,10 @@ void ComboField::UpdateWidgetValue(QWidget *widget, double timecode) void ComboField::UpdateFromWidget(int index) { + KeyframeDataChange* kdc = new KeyframeDataChange(this); + SetValueAt(Now(), items_.at(index).data); + + kdc->SetNewKeyframes(); + olive::UndoStack.push(kdc); } diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 8499c2f9b..18ff66740 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -1,6 +1,6 @@ #include "doublefield.h" -#include +#include "effects/effectrow.h" DoubleField::DoubleField(EffectRow* parent, const QString& id) : EffectField(parent, id, EFFECT_FIELD_DOUBLE), @@ -9,7 +9,8 @@ DoubleField::DoubleField(EffectRow* parent, const QString& id) : default_(0), display_type_(LabelSlider::Normal), frame_rate_(30), - value_set_(false) + value_set_(false), + kdc_(nullptr) { connect(this, SIGNAL(Changed()), this, SLOT(ValueHasBeenSet()), Qt::DirectConnection); } @@ -94,5 +95,18 @@ void DoubleField::ValueHasBeenSet() void DoubleField::UpdateFromWidget(double d) { + LabelSlider* ls = static_cast(sender()); + + if (ls->IsDragging() && kdc_ == nullptr) { + kdc_ = new KeyframeDataChange(this); + } + SetValueAt(Now(), d); + GetParentRow()->SetKeyframeOnAllFields(nullptr); + + if (!ls->IsDragging() && kdc_ != nullptr) { + kdc_->SetNewKeyframes(); + olive::UndoStack.push(kdc_); + kdc_ = nullptr; + } } diff --git a/effects/fields/doublefield.h b/effects/fields/doublefield.h index 39a46a334..935e895bf 100644 --- a/effects/fields/doublefield.h +++ b/effects/fields/doublefield.h @@ -46,6 +46,8 @@ private: double frame_rate_; bool value_set_; + + KeyframeDataChange* kdc_; private slots: void ValueHasBeenSet(); void UpdateFromWidget(double d); diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp index a76383e15..27698c94c 100644 --- a/effects/fields/filefield.cpp +++ b/effects/fields/filefield.cpp @@ -25,5 +25,10 @@ QWidget *FileField::CreateWidget() void FileField::UpdateFromWidget(const QString &s) { + KeyframeDataChange* kdc = new KeyframeDataChange(this); + SetValueAt(Now(), s); + + kdc->SetNewKeyframes(); + olive::UndoStack.push(kdc); } diff --git a/effects/fields/fontfield.cpp b/effects/fields/fontfield.cpp index 9c7343225..c95c87697 100644 --- a/effects/fields/fontfield.cpp +++ b/effects/fields/fontfield.cpp @@ -54,5 +54,10 @@ void FontField::UpdateWidgetValue(QWidget *widget, double timecode) void FontField::UpdateFromWidget(const QString& s) { + KeyframeDataChange* kdc = new KeyframeDataChange(this); + SetValueAt(Now(), s); + + kdc->SetNewKeyframes(); + olive::UndoStack.push(kdc); } diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index b885ef035..777a0fdfc 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -41,5 +41,10 @@ void StringField::UpdateWidgetValue(QWidget *widget, double timecode) void StringField::UpdateFromWidget(const QString &s) { + KeyframeDataChange* kdc = new KeyframeDataChange(this); + SetValueAt(Now(), s); + + kdc->SetNewKeyframes(); + olive::UndoStack.push(kdc); } diff --git a/ui/checkboxex.cpp b/ui/checkboxex.cpp index 25d812253..b42c7159e 100644 --- a/ui/checkboxex.cpp +++ b/ui/checkboxex.cpp @@ -20,13 +20,13 @@ #include "checkboxex.h" -#include "project/undo.h" +#include "undo/undo.h" CheckboxEx::CheckboxEx(QWidget* parent) : QCheckBox(parent) { // connect(this, SIGNAL(clicked(bool)), this, SLOT(checkbox_command())); } void CheckboxEx::checkbox_command() { - CheckboxCommand* c = new CheckboxCommand(this); - olive::UndoStack.push(c); + CheckboxCommand* c = new CheckboxCommand(this); + olive::UndoStack.push(c); } diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index dd0e9ced9..a75ec85a5 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -33,7 +33,7 @@ #include "ui/checkboxex.h" #include "ui/icons.h" -#include "debug.h" +#include "global/debug.h" CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { selected = false; diff --git a/ui/colorbutton.cpp b/ui/colorbutton.cpp index a5e200fbc..e841707b1 100644 --- a/ui/colorbutton.cpp +++ b/ui/colorbutton.cpp @@ -20,8 +20,6 @@ #include "colorbutton.h" -#include "project/undo.h" - #include ColorButton::ColorButton(QWidget *parent) @@ -58,14 +56,3 @@ void ColorButton::open_dialog() { emit color_changed(color); } } - -ColorCommand::ColorCommand(ColorButton* s, QColor o, QColor n) - : sender(s), old_color(o), new_color(n) {} - -void ColorCommand::undo() { - sender->set_color(old_color); -} - -void ColorCommand::redo() { - sender->set_color(new_color); -} diff --git a/ui/colorbutton.h b/ui/colorbutton.h index 74364d951..944378b8c 100644 --- a/ui/colorbutton.h +++ b/ui/colorbutton.h @@ -42,15 +42,4 @@ private slots: void open_dialog(); }; -class ColorCommand : public QUndoCommand { -public: - ColorCommand(ColorButton* s, QColor o, QColor n); - void undo(); - void redo(); -private: - ColorButton* sender; - QColor old_color; - QColor new_color; -}; - #endif // COLORBUTTON_H diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 6305c6116..f8c60aa37 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -66,6 +66,8 @@ EffectUI::EffectUI(Effect* e) : KeyframeNavigator* nav = new KeyframeNavigator(); + nav->enable_keyframes(row->IsKeyframing()); + connect(nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); connect(nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); diff --git a/ui/icons.cpp b/ui/icons.cpp index 0e3eff232..eae5ba1f3 100644 --- a/ui/icons.cpp +++ b/ui/icons.cpp @@ -1,5 +1,7 @@ #include "icons.h" +#include + #include "global/global.h" #include "global/config.h" diff --git a/ui/keyframedrawing.cpp b/ui/keyframedrawing.cpp index e282cafdf..568ab3533 100644 --- a/ui/keyframedrawing.cpp +++ b/ui/keyframedrawing.cpp @@ -20,8 +20,8 @@ #include "keyframedrawing.h" -#include "project/effect.h" -#include "project/clip.h" +#include "effects/effect.h" +#include "timeline/clip.h" #define KEYFRAME_POINT_COUNT 4 diff --git a/ui/keyframenavigator.cpp b/ui/keyframenavigator.cpp index 18625b26d..c27e07415 100644 --- a/ui/keyframenavigator.cpp +++ b/ui/keyframenavigator.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "ui/icons.h" diff --git a/ui/keyframenavigator.h b/ui/keyframenavigator.h index 772a1f8f7..3811b3906 100644 --- a/ui/keyframenavigator.h +++ b/ui/keyframenavigator.h @@ -34,6 +34,7 @@ public: ~KeyframeNavigator(); void enable_keyframe_toggle(bool); +public slots: void enable_keyframes(bool); signals: void goto_previous_key(); diff --git a/ui/resizablescrollbar.cpp b/ui/resizablescrollbar.cpp index aa23c960a..785f2eba8 100644 --- a/ui/resizablescrollbar.cpp +++ b/ui/resizablescrollbar.cpp @@ -24,7 +24,7 @@ #include #include -#include "debug.h" +#include "global/debug.h" #define RESIZE_HANDLE_SIZE 10 diff --git a/ui/sourcetable.h b/ui/sourcetable.h index 94868decc..251d87776 100644 --- a/ui/sourcetable.h +++ b/ui/sourcetable.h @@ -30,19 +30,19 @@ class Media; class SourceTable : public QTreeView { - Q_OBJECT + Q_OBJECT public: - SourceTable(QWidget* parent = 0); - Project* project_parent; + SourceTable(QWidget* parent = 0); + Project* project_parent; protected: - void mousePressEvent(QMouseEvent*); - void mouseDoubleClickEvent(QMouseEvent *); - void dragEnterEvent(QDragEnterEvent *event); - void dragMoveEvent(QDragMoveEvent *event); - void dropEvent(QDropEvent *event); + void mousePressEvent(QMouseEvent*); + void mouseDoubleClickEvent(QMouseEvent *); + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); private slots: - void item_click(const QModelIndex& index); - void show_context_menu(); + void item_click(const QModelIndex& index); + void show_context_menu(); }; #endif // SOURCETABLE_H diff --git a/undo/undo.cpp b/undo/undo.cpp index e30228e9b..725516b2c 100644 --- a/undo/undo.cpp +++ b/undo/undo.cpp @@ -607,22 +607,6 @@ void KeyframeDelete::doRedo() { field->keyframes.removeAt(index); } -/* -EffectFieldUndo::EffectFieldUndo(EffectField* f, const QVariant& old_data, const QVariant new_data) : - field(f), - old_val(old_data), - new_val(new_data) -{} - -void EffectFieldUndo::doUndo() { - field->SetCurrentValue(old_val); -} - -void EffectFieldUndo::doRedo() { - field->SetCurrentValue(new_val); -} -*/ - SetClipProperty::SetClipProperty(SetClipPropertyType type) : type_(type) {} @@ -1169,3 +1153,29 @@ void OliveAction::redo() { } } + +KeyframeDataChange::KeyframeDataChange(EffectField *field) : + field_(field), + done_(true) +{ + old_keys_ = field_->keyframes; +} + +void KeyframeDataChange::SetNewKeyframes() +{ + new_keys_ = field_->keyframes; +} + +void KeyframeDataChange::doUndo() +{ + field_->keyframes = old_keys_; + done_ = false; +} + +void KeyframeDataChange::doRedo() +{ + if (!done_) { + field_->keyframes = new_keys_; + done_ = true; + } +} diff --git a/undo/undo.h b/undo/undo.h index 4327839f2..6ec38c988 100644 --- a/undo/undo.h +++ b/undo/undo.h @@ -28,15 +28,30 @@ #include #include -#include "project/projectelements.h" -#include "timeline/selection.h" -#include "timeline/clip.h" -#include "timeline/sequence.h" -#include "effects/transition.h" -#include "effects/effectfield.h" +#include "comboaction.h" -#include "ui/labelslider.h" -#include "ui/sourcetable.h" +#include "timeline/marker.h" +#include "timeline/selection.h" +#include "effects/keyframe.h" + +class Clip; +using ClipPtr = std::shared_ptr; + +class Sequence; +using SequencePtr = std::shared_ptr; + +class Media; +using MediaPtr = std::shared_ptr; + +class Effect; +using EffectPtr = std::shared_ptr; + +class Transition; +using TransitionPtr = std::shared_ptr; + +struct EffectMeta; +class EffectRow; +class EffectField; namespace olive { extern QUndoStack UndoStack; @@ -334,18 +349,6 @@ private: bool done; }; -class EffectFieldUndo : public OliveAction { -public: - EffectFieldUndo(EffectField* field, const QVariant &old_data, const QVariant new_data); - virtual void doUndo() override; - virtual void doRedo() override; -private: - EffectField* field; - QVariant old_val; - QVariant new_val; - bool done; -}; - enum SetClipPropertyType { kSetClipPropertyAutoscale, kSetClipPropertyReversed, @@ -620,4 +623,20 @@ private: QByteArray old_data; }; +class KeyframeDataChange : public OliveAction { +public: + KeyframeDataChange(EffectField* field); + + void SetNewKeyframes(); + + virtual void doUndo() override; + virtual void doRedo() override; + +private: + EffectField* field_; + QVector old_keys_; + QVector new_keys_; + bool done_; +}; + #endif // UNDO_H From e3e322ca53320b15cb7ca36c29b5d7819206d510 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 13 Mar 2019 22:46:53 +1100 Subject: [PATCH 26/56] connected effect UI to enabled setting --- effects/effect.h | 2 +- effects/fields/doublefield.cpp | 3 ++- ui/collapsiblewidget.cpp | 8 ++------ ui/collapsiblewidget.h | 1 - ui/effectui.cpp | 4 +++- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/effects/effect.h b/effects/effect.h index 325406836..89d4dfbf9 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -154,7 +154,6 @@ public: int gizmo_count(); bool IsEnabled(); - void SetEnabled(bool b); virtual void refresh(); @@ -214,6 +213,7 @@ public: static const EffectMeta* GetInternalMeta(int internal_id, int type); public slots: void FieldChanged(); + void SetEnabled(bool b); signals: void EnabledChanged(bool); private slots: diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 18ff66740..42c58488b 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -102,11 +102,12 @@ void DoubleField::UpdateFromWidget(double d) } SetValueAt(Now(), d); - GetParentRow()->SetKeyframeOnAllFields(nullptr); if (!ls->IsDragging() && kdc_ != nullptr) { kdc_->SetNewKeyframes(); + olive::UndoStack.push(kdc_); + kdc_ = nullptr; } } diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index a75ec85a5..fb3e94bc6 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -52,7 +52,7 @@ CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { header = new QLabel(title_bar); collapse_button = new QPushButton(title_bar); collapse_button->setIconSize(collapse_button->iconSize()*0.5); - collapse_button->setStyleSheet("QPushButton { border: none; }"); + collapse_button->setFlat(true); SetText(tr("")); title_bar_layout->addWidget(collapse_button); title_bar_layout->addWidget(enabled_check); @@ -103,7 +103,7 @@ void CollapsibleWidget::SetContents(QWidget* c) { contents = c; if (!existing) { layout->addWidget(contents); - connect(enabled_check, SIGNAL(toggled(bool)), this, SLOT(on_enabled_change(bool))); + connect(enabled_check, SIGNAL(toggled(bool)), contents, SLOT(setEnabled(bool))); connect(collapse_button, SIGNAL(clicked()), this, SLOT(on_visible_change())); } } @@ -112,10 +112,6 @@ void CollapsibleWidget::SetText(const QString &s) { header->setText(s); } -void CollapsibleWidget::on_enabled_change(bool b) { - contents->setEnabled(b); -} - void CollapsibleWidget::on_visible_change() { contents->setVisible(!contents->isVisible()); set_button_icon(contents->isVisible()); diff --git a/ui/collapsiblewidget.h b/ui/collapsiblewidget.h index ad512bb3a..d13ebd300 100644 --- a/ui/collapsiblewidget.h +++ b/ui/collapsiblewidget.h @@ -72,7 +72,6 @@ signals: void visibleChanged(); private slots: - void on_enabled_change(bool b); void on_visible_change(); public slots: diff --git a/ui/effectui.cpp b/ui/effectui.cpp index f8c60aa37..62652e7ab 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -78,7 +78,9 @@ EffectUI::EffectUI(Effect* e) : layout_->addWidget(nav, i, maximum_column); } - connect(enabled_check, SIGNAL(clicked(bool)), e, SLOT(FieldChanged())); + enabled_check->setChecked(e->IsEnabled()); + connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(FieldChanged())); + connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(SetEnabled(bool))); } Effect *EffectUI::GetEffect() From d442b30abac9d926c90376dc1cf9e7cd092c9e7e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 07:44:28 +1100 Subject: [PATCH 27/56] update effect controls after setting effects --- panels/effectcontrols.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 326016598..1e8708ca8 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -629,6 +629,7 @@ void EffectControls::Load() { } UpdateTitle(); + update_keyframes(); } void EffectControls::video_effect_click() { From aeadb73679836e132469176f817c259dcef93339 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 08:14:01 +1100 Subject: [PATCH 28/56] updated script for new shader directory --- .travis/script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/script.sh b/.travis/script.sh index 16d02789d..bb5d4edcb 100644 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -24,7 +24,7 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then # move external effects into bundle mkdir Olive.app/Contents/Effects - cp effects/* Olive.app/Contents/Effects + cp effects/shaders/* Olive.app/Contents/Effects # distribute in zip zip -r Olive-$(git rev-parse --short HEAD)-macOS.zip Olive.app From b884f7511b21f86ddf0443f7feba54ba0b6e446a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 08:15:12 +1100 Subject: [PATCH 29/56] reimplemented gizmos --- effects/effect.cpp | 64 ++++++++++++++++++++++++++++++++++------- effects/effect.h | 2 ++ effects/effectfield.cpp | 14 ++++----- effects/effectfield.h | 2 +- olive.pro | 2 +- ui/viewerwidget.cpp | 2 -- undo/undo.cpp | 4 +++ undo/undo.h | 2 ++ 8 files changed, 70 insertions(+), 22 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index dec9b4d38..c35752b14 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -896,27 +896,69 @@ void Effect::process_audio(double, double, quint8*, int, int) {} void Effect::gizmo_draw(double, GLTextureCoords &) {} void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) { + // Loop through each gizmo to find `gizmo` for (int i=0;ix_field1 != nullptr) { + gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->x_field1)); + } + if (gizmo->y_field1 != nullptr) { + gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->y_field1)); + } + if (gizmo->x_field2 != nullptr) { + gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->x_field2)); + } + if (gizmo->y_field2 != nullptr) { + gizmo_dragging_actions_.append(new KeyframeDataChange(gizmo->y_field2)); + } + } + + // Update the field values if (gizmo->x_field1 != nullptr) { - gizmo->x_field1->SetValueAt(timecode, gizmo->x_field1->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi1); - //gizmo->x_field1->make_key_from_change(ca); + gizmo->x_field1->SetValueAt(timecode, + gizmo->x_field1->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi1); } if (gizmo->y_field1 != nullptr) { - gizmo->y_field1->SetValueAt(timecode, gizmo->y_field1->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi1); - //gizmo->y_field1->make_key_from_change(ca); + gizmo->y_field1->SetValueAt(timecode, + gizmo->y_field1->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi1); } if (gizmo->x_field2 != nullptr) { - gizmo->x_field2->SetValueAt(timecode, gizmo->x_field2->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi2); - //gizmo->x_field2->make_key_from_change(ca); + gizmo->x_field2->SetValueAt(timecode, + gizmo->x_field2->GetDoubleAt(timecode) + x_movement*gizmo->x_field_multi2); } if (gizmo->y_field2 != nullptr) { - gizmo->y_field2->SetValueAt(timecode, gizmo->y_field2->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi2); - //gizmo->y_field2->make_key_from_change(ca); + gizmo->y_field2->SetValueAt(timecode, + gizmo->y_field2->GetDoubleAt(timecode) + y_movement*gizmo->y_field_multi2); + } + + // If (done && !gizmo_dragging_actions_.isEmpty()), that means the drag just ended and we're going to save + // the new state of the attach fields' keyframes in KeyframeDataChange objects to make the changes undoable + // by the user later. + if (done && !gizmo_dragging_actions_.isEmpty()) { + + // Store all the KeyframeDataChange objects into a ComboAction to send to the undo stack (makes them all + // undoable together rather than having to be undone individually). + ComboAction* ca = new ComboAction(); + + for (int j=0;jSetNewKeyframes(); + + // Add this KeyframeDataChange object to the ComboAction + ca->append(gizmo_dragging_actions_.at(j)); + } + + olive::UndoStack.push(ca); + + gizmo_dragging_actions_.clear(); } - if (done) olive::UndoStack.push(ca); break; } } diff --git a/effects/effect.h b/effects/effect.h index 89d4dfbf9..dd0780c5a 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -246,6 +246,8 @@ private: int flags_; + QVector gizmo_dragging_actions_; + // enable effect to update constantly bool enable_always_update_; diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index 73aabc02d..23c863060 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -179,7 +179,7 @@ QVariant EffectField::GetValueAt(double timecode) } } - perpetual_data_ = value; + persistent_data_ = value; break; } case EFFECT_FIELD_COLOR: @@ -192,7 +192,7 @@ QVariant EffectField::GetValueAt(double timecode) QColor after_data = keyframes.at(after_keyframe).data.value(); 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)); } - perpetual_data_ = value; + persistent_data_ = value; break; } case EFFECT_FIELD_STRING: @@ -200,14 +200,14 @@ QVariant EffectField::GetValueAt(double timecode) case EFFECT_FIELD_COMBO: case EFFECT_FIELD_FONT: case EFFECT_FIELD_FILE: - perpetual_data_ = before_data; + persistent_data_ = before_data; break; default: break; } } - return perpetual_data_; + return persistent_data_; } void EffectField::SetValueAt(double time, const QVariant &value) @@ -241,7 +241,7 @@ void EffectField::SetValueAt(double time, const QVariant &value) } } else { - perpetual_data_ = value; + persistent_data_ = value; } emit Changed(); @@ -267,7 +267,7 @@ void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) EffectKeyframe key; key.time = NowInFrames(); - key.data = perpetual_data_; + key.data = persistent_data_; key.type = EFFECT_KEYFRAME_LINEAR; keyframes.append(key); @@ -279,7 +279,7 @@ void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca) // Convert keyframes to one "perpetual" keyframe // Set first keyframe to whatever the data is now - ca->append(new SetQVariant(&perpetual_data_, perpetual_data_, GetValueAt(Now()))); + ca->append(new SetQVariant(&persistent_data_, persistent_data_, GetValueAt(Now()))); // Delete all keyframes for (int i=0;i keyframes; signals: @@ -95,7 +96,6 @@ private: bool enabled_; int colspan_; - QVariant perpetual_data_; }; #endif // EFFECTFIELD_H diff --git a/olive.pro b/olive.pro index f559cbf16..59319e67c 100644 --- a/olive.pro +++ b/olive.pro @@ -344,7 +344,7 @@ unix:!mac:isEmpty(PREFIX) { unix:!mac:target.path = $$PREFIX/bin -effects.files = $$PWD/effects/*.frag $$PWD/effects/*.xml $$PWD/effects/*.vert +effects.files = $$PWD/effects/shaders/* unix:!mac:effects.path = $$PREFIX/share/olive-editor/effects translations.files = $$PWD/ts/*.qm diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 5901098b0..37a24d540 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -310,8 +310,6 @@ void ViewerWidget::move_gizmos(QMouseEvent *event, bool done) { drag_start_x = event->pos().x(); drag_start_y = event->pos().y(); - - gizmos->FieldChanged(); } } diff --git a/undo/undo.cpp b/undo/undo.cpp index 725516b2c..23d3429bc 100644 --- a/undo/undo.cpp +++ b/undo/undo.cpp @@ -1159,16 +1159,19 @@ KeyframeDataChange::KeyframeDataChange(EffectField *field) : done_(true) { old_keys_ = field_->keyframes; + old_persistent_data_ = field_->persistent_data_; } void KeyframeDataChange::SetNewKeyframes() { new_keys_ = field_->keyframes; + new_persistent_data_ = field_->persistent_data_; } void KeyframeDataChange::doUndo() { field_->keyframes = old_keys_; + field_->persistent_data_ = old_persistent_data_; done_ = false; } @@ -1176,6 +1179,7 @@ void KeyframeDataChange::doRedo() { if (!done_) { field_->keyframes = new_keys_; + field_->persistent_data_ = new_persistent_data_; done_ = true; } } diff --git a/undo/undo.h b/undo/undo.h index 6ec38c988..11853f818 100644 --- a/undo/undo.h +++ b/undo/undo.h @@ -636,6 +636,8 @@ private: EffectField* field_; QVector old_keys_; QVector new_keys_; + QVariant old_persistent_data_; + QVariant new_persistent_data_; bool done_; }; From 1508e3cf73cd10dc5141ed4c6ef446ff8a4f9528 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 08:51:22 +1100 Subject: [PATCH 30/56] fixed #624 --- ui/mainwindow.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index ca7b47eec..c06ec97b2 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -547,45 +547,58 @@ void MainWindow::setup_menus() { view_menu->addSeparator(); + QActionGroup* frame_view_mode_group = new QActionGroup(this); + frames_action = MenuHelper::create_menu_action(view_menu, "modeframes", &olive::MenuHelper, SLOT(set_timecode_view())); frames_action->setData(olive::kTimecodeFrames); frames_action->setCheckable(true); + frame_view_mode_group->addAction(frames_action); drop_frame_action = MenuHelper::create_menu_action(view_menu, "modedropframe", &olive::MenuHelper, SLOT(set_timecode_view())); drop_frame_action->setData(olive::kTimecodeDrop); drop_frame_action->setCheckable(true); + frame_view_mode_group->addAction(drop_frame_action); nondrop_frame_action = MenuHelper::create_menu_action(view_menu, "modenondropframe", &olive::MenuHelper, SLOT(set_timecode_view())); nondrop_frame_action->setData(olive::kTimecodeNonDrop); nondrop_frame_action->setCheckable(true); + frame_view_mode_group->addAction(nondrop_frame_action); milliseconds_action = MenuHelper::create_menu_action(view_menu, "milliseconds", &olive::MenuHelper, SLOT(set_timecode_view())); milliseconds_action->setData(olive::kTimecodeMilliseconds); milliseconds_action->setCheckable(true); + frame_view_mode_group->addAction(milliseconds_action); view_menu->addSeparator(); title_safe_area_menu = MenuHelper::create_submenu(view_menu); + QActionGroup* title_safe_group = new QActionGroup(this); + title_safe_off = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafeoff", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); title_safe_off->setCheckable(true); title_safe_off->setData(qSNaN()); + title_safe_group->addAction(title_safe_off); title_safe_default = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafedefault", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); title_safe_default->setCheckable(true); title_safe_default->setData(0.0); + title_safe_group->addAction(title_safe_default); title_safe_43 = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafe43", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); title_safe_43->setCheckable(true); title_safe_43->setData(4.0/3.0); + title_safe_group->addAction(title_safe_43); title_safe_169 = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafe169", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); title_safe_169->setCheckable(true); title_safe_169->setData(16.0/9.0); + title_safe_group->addAction(title_safe_169); title_safe_custom = MenuHelper::create_menu_action(title_safe_area_menu, "titlesafecustom", &olive::MenuHelper, SLOT(set_titlesafe_from_menu())); title_safe_custom->setCheckable(true); title_safe_custom->setData(-1.0); + title_safe_group->addAction(title_safe_custom); view_menu->addSeparator(); @@ -671,37 +684,47 @@ void MainWindow::setup_menus() { tools_menu = MenuHelper::create_submenu(menuBar, this, SLOT(toolMenu_About_To_Be_Shown())); tools_menu->setToolTipsVisible(true); + QActionGroup* tools_group = new QActionGroup(this); + pointer_tool_action = MenuHelper::create_menu_action(tools_menu, "pointertool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("V")); pointer_tool_action->setCheckable(true); pointer_tool_action->setData(reinterpret_cast(panel_timeline->toolArrowButton)); + tools_group->addAction(pointer_tool_action); edit_tool_action = MenuHelper::create_menu_action(tools_menu, "edittool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("X")); edit_tool_action->setCheckable(true); edit_tool_action->setData(reinterpret_cast(panel_timeline->toolEditButton)); + tools_group->addAction(edit_tool_action); ripple_tool_action = MenuHelper::create_menu_action(tools_menu, "rippletool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("B")); ripple_tool_action->setCheckable(true); ripple_tool_action->setData(reinterpret_cast(panel_timeline->toolRippleButton)); + tools_group->addAction(ripple_tool_action); razor_tool_action = MenuHelper::create_menu_action(tools_menu, "razortool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("C")); razor_tool_action->setCheckable(true); razor_tool_action->setData(reinterpret_cast(panel_timeline->toolRazorButton)); + tools_group->addAction(razor_tool_action); slip_tool_action = MenuHelper::create_menu_action(tools_menu, "sliptool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("Y")); slip_tool_action->setCheckable(true); slip_tool_action->setData(reinterpret_cast(panel_timeline->toolSlipButton)); + tools_group->addAction(slip_tool_action); slide_tool_action = MenuHelper::create_menu_action(tools_menu, "slidetool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("U")); slide_tool_action->setCheckable(true); slide_tool_action->setData(reinterpret_cast(panel_timeline->toolSlideButton)); + tools_group->addAction(slide_tool_action); hand_tool_action = MenuHelper::create_menu_action(tools_menu, "handtool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("H")); hand_tool_action->setCheckable(true); hand_tool_action->setData(reinterpret_cast(panel_timeline->toolHandButton)); + tools_group->addAction(hand_tool_action); transition_tool_action = MenuHelper::create_menu_action(tools_menu, "transitiontool", &olive::MenuHelper, SLOT(menu_click_button()), QKeySequence("T")); transition_tool_action->setCheckable(true); transition_tool_action->setData(reinterpret_cast(panel_timeline->toolTransitionButton)); + tools_group->addAction(transition_tool_action); tools_menu->addSeparator(); @@ -769,17 +792,22 @@ void MainWindow::setup_menus() { tools_menu->addSeparator(); + QActionGroup* autoscroll_group = new QActionGroup(this); + no_autoscroll = MenuHelper::create_menu_action(tools_menu, "autoscrollno", &olive::MenuHelper, SLOT(set_autoscroll())); no_autoscroll->setData(olive::AUTOSCROLL_NO_SCROLL); no_autoscroll->setCheckable(true); + autoscroll_group->addAction(no_autoscroll); page_autoscroll = MenuHelper::create_menu_action(tools_menu, "autoscrollpage", &olive::MenuHelper, SLOT(set_autoscroll())); page_autoscroll->setData(olive::AUTOSCROLL_PAGE_SCROLL); page_autoscroll->setCheckable(true); + autoscroll_group->addAction(page_autoscroll); smooth_autoscroll = MenuHelper::create_menu_action(tools_menu, "autoscrollsmooth", &olive::MenuHelper, SLOT(set_autoscroll())); smooth_autoscroll->setData(olive::AUTOSCROLL_SMOOTH_SCROLL); smooth_autoscroll->setCheckable(true); + autoscroll_group->addAction(smooth_autoscroll); tools_menu->addSeparator(); From 7b7ffc84d29f9ceaac01e64bc502be126f20adbc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 08:51:45 +1100 Subject: [PATCH 31/56] use make_unique rather than new for mediaiconservice --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index ed250177e..438d026a7 100644 --- a/main.cpp +++ b/main.cpp @@ -119,7 +119,7 @@ int main(int argc, char *argv[]) { a.setWindowIcon(QIcon(":/icons/olive64.png")); // start media icon service (uses QPixmaps which require a QGuiApplication to have been created) - olive::media_icon_service = std::unique_ptr(new MediaIconService()); + olive::media_icon_service = std::make_unique(); // set app name data QCoreApplication::setOrganizationName("olivevideoeditor.org"); From c6a4b9e8d6c55468671a7690cceffe0cfb64f5e1 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 09:35:50 +1100 Subject: [PATCH 32/56] fixed the graph editor --- effects/effect.cpp | 10 ++++++++ panels/effectcontrols.cpp | 24 ++++++++++++++---- panels/grapheditor.cpp | 51 +++++++++++++++------------------------ panels/grapheditor.h | 10 ++++---- ui/graphview.cpp | 1 - 5 files changed, 54 insertions(+), 42 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index c35752b14..6197f7601 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -339,6 +339,16 @@ Effect::~Effect() { if (isOpen) { close(); } + + // Clear graph editor if it's using one of these rows + if (panel_graph_editor != nullptr) { + for (int i=0;iget_row()) { + panel_graph_editor->set_row(nullptr); + break; + } + } + } } void Effect::AddRow(EffectRow *row) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 1e8708ca8..dacdd7322 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -273,11 +273,6 @@ void EffectControls::Clear(bool clear_cache) { // clear existing clips deselect_all_effects(nullptr); - // clear graph editor - if (panel_graph_editor != nullptr) { - panel_graph_editor->set_row(nullptr); - } - for (int i=0;i &clips, int mode) } void EffectControls::Load() { + bool graph_editor_row_is_still_active = false; + // load in new clips for (int i=0;ieffects.size();j++) { open_effect(layout, c->effects.at(j).get()); + + // Check if one of the open effects contains the row currently active in the graph editor. If not, we'll have + // to clear the graph editor later. + if (!graph_editor_row_is_still_active) { + for (int k=0;keffects.at(j)->row_count();k++) { + EffectRow* row = c->effects.at(j)->row(k); + if (row == panel_graph_editor->get_row()) { + graph_editor_row_is_still_active = true; + break; + } + } + } } } else if (mode_ == kTransitionOpening && c->opening_transition != nullptr) { open_effect(layout, c->opening_transition.get()); @@ -628,6 +637,11 @@ void EffectControls::Load() { QTimer::singleShot(50, this, SLOT(queue_post_update())); } + // If the graph editor's currently active row is not part of the current effects, clear it + if (!graph_editor_row_is_still_active) { + panel_graph_editor->set_row(nullptr); + } + UpdateTitle(); update_keyframes(); } diff --git a/panels/grapheditor.cpp b/panels/grapheditor.cpp index 6f720da10..17897a9ab 100644 --- a/panels/grapheditor.cpp +++ b/panels/grapheditor.cpp @@ -130,6 +130,11 @@ GraphEditor::GraphEditor(QWidget* parent) : Panel(parent), row(nullptr) { Retranslate(); } +EffectRow *GraphEditor::get_row() +{ + return row; +} + void GraphEditor::Retranslate() { setWindowTitle(tr("Graph Editor")); linear_button->setText(tr("Linear")); @@ -144,11 +149,7 @@ void GraphEditor::update_panel() { for (int i=0;iFieldCount();i++) { EffectField* field = row->Field(i); if (field->type() == EffectField::EFFECT_FIELD_DOUBLE) { - slider_proxies.at(slider_index)->SetValue( - row->Field(i)->GetValueAt( - playhead_to_clip_seconds(field->GetParentRow()->GetParentEffect()->parent_clip, - olive::ActiveSequence->playhead)).toDouble() - ); + field->UpdateWidgetValue(field_sliders_.at(slider_index), field->Now()); slider_index++; } } @@ -160,19 +161,18 @@ void GraphEditor::update_panel() { } void GraphEditor::set_row(EffectRow *r) { - for (int i=0;isetProperty("field", i); slider_button->setIconSize(slider_button->iconSize()*0.5); connect(slider_button, SIGNAL(toggled(bool)), this, SLOT(set_field_visibility(bool))); - slider_proxy_buttons.append(slider_button); + field_enable_buttons.append(slider_button); value_layout->addWidget(slider_button); - LabelSlider* slider = new LabelSlider(); + LabelSlider* slider = static_cast(field->CreateWidget()); slider->SetColor(get_curve_color(i, r->FieldCount()).name()); - connect(slider, SIGNAL(valueChanged()), this, SLOT(passthrough_slider_value())); - slider_proxies.append(slider); + field_sliders_.append(slider); value_layout->addWidget(slider); - //slider_proxy_sources.append(static_cast(field->ui_element)); - found_vals = true; } } @@ -211,9 +208,9 @@ void GraphEditor::set_row(EffectRow *r) { + " :: " + row->name()); header->set_visible_in(r->GetParentEffect()->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())); + connect(keyframe_nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); + connect(keyframe_nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); + connect(keyframe_nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); } else { row = nullptr; current_row_desc->setText(nullptr); @@ -247,14 +244,6 @@ void GraphEditor::set_key_button_enabled(bool e, int type) { hold_button->setChecked(type == EFFECT_KEYFRAME_HOLD); } -void GraphEditor::passthrough_slider_value() { - for (int i=0;iSetValue(slider_proxies.at(i)->value()); - } - } -} - void GraphEditor::set_keyframe_type() { linear_button->setChecked(linear_button == sender()); bezier_button->setChecked(bezier_button == sender()); diff --git a/panels/grapheditor.h b/panels/grapheditor.h index 0ba0f3136..d7fb2fdc7 100644 --- a/panels/grapheditor.h +++ b/panels/grapheditor.h @@ -37,8 +37,10 @@ class GraphEditor : public Panel { public: GraphEditor(QWidget* parent = nullptr); - void update_panel(); + EffectRow* get_row(); void set_row(EffectRow* r); + + void update_panel(); bool view_is_focused(); bool view_is_under_mouse(); void delete_selected_keys(); @@ -50,9 +52,8 @@ private: GraphView* view; TimelineHeader* header; QHBoxLayout* value_layout; - QVector slider_proxies; - QVector slider_proxy_buttons; - QVector slider_proxy_sources; + QVector field_sliders_; + QVector field_enable_buttons; QLabel* current_row_desc; EffectRow* row; KeyframeNavigator* keyframe_nav; @@ -61,7 +62,6 @@ private: 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); }; diff --git a/ui/graphview.cpp b/ui/graphview.cpp index f6b6cd124..7cade8cda 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -38,7 +38,6 @@ #include "ui/rectangleselect.h" #include "global/debug.h" - const double kGraphZoomSpeed = 0.05; const int kGraphSize = 100; const int kBezierHandleSize = 3; From c73fc780871ec445edbb939de1ec68fed790915f Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 10:53:50 +1100 Subject: [PATCH 33/56] moved undostack to its own source file --- dialogs/mediapropertiesdialog.cpp | 1 + dialogs/newsequencedialog.cpp | 1 + dialogs/preferencesdialog.cpp | 6 +++ dialogs/preferencesdialog.h | 10 +++++ dialogs/replaceclipmediadialog.cpp | 10 ++--- dialogs/speeddialog.cpp | 1 + effects/effect.cpp | 30 +++++++------ effects/effectfield.h | 1 + effects/effectgizmo.cpp | 10 ----- effects/effectgizmo.h | 2 - effects/effectrow.cpp | 1 + effects/internal/cornerpineffect.cpp | 2 +- effects/keyframe.cpp | 1 + global/global.cpp | 25 ++++++----- olive.pro | 6 ++- panels/effectcontrols.cpp | 1 + panels/project.cpp | 6 +++ panels/timeline.cpp | 5 +++ panels/viewer.cpp | 11 +++-- project/media.cpp | 1 + project/sourcescommon.cpp | 18 ++++---- timeline/marker.cpp | 15 ++++--- timeline/marker.h | 4 +- timeline/sequence.cpp | 13 +++--- ui/checkboxex.cpp | 1 + ui/graphview.cpp | 1 + ui/keyframeview.cpp | 9 ++-- ui/mainwindow.cpp | 52 +++++++++------------ ui/menuhelper.cpp | 20 ++++++--- ui/menuhelper.h | 7 ++- ui/timelineheader.cpp | 15 ++++--- ui/timelinewidget.cpp | 67 +++++++++++++--------------- ui/viewerwidget.cpp | 4 -- undo/undo.cpp | 10 ++--- undo/undo.h | 4 -- undo/undostack.cpp | 3 ++ undo/undostack.h | 10 +++++ 37 files changed, 212 insertions(+), 172 deletions(-) create mode 100644 undo/undostack.cpp create mode 100644 undo/undostack.h diff --git a/dialogs/mediapropertiesdialog.cpp b/dialogs/mediapropertiesdialog.cpp index dceb5ba9a..3ea790c55 100644 --- a/dialogs/mediapropertiesdialog.cpp +++ b/dialogs/mediapropertiesdialog.cpp @@ -35,6 +35,7 @@ #include "project/media.h" #include "panels/project.h" #include "undo/undo.h" +#include "undo/undostack.h" MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) : QDialog(parent), diff --git a/dialogs/newsequencedialog.cpp b/dialogs/newsequencedialog.cpp index 575775af7..8f12077c6 100644 --- a/dialogs/newsequencedialog.cpp +++ b/dialogs/newsequencedialog.cpp @@ -23,6 +23,7 @@ #include "panels/panels.h" #include "panels/project.h" #include "timeline/sequence.h" +#include "undo/undostack.h" #include "undo/undo.h" #include "timeline/clip.h" #include "panels/timeline.h" diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp index e5115e906..af9ebdbbf 100644 --- a/dialogs/preferencesdialog.cpp +++ b/dialogs/preferencesdialog.cpp @@ -544,6 +544,12 @@ void PreferencesDialog::setup_ui() { use_software_fallbacks_checkbox->setChecked(olive::CurrentConfig.use_software_fallback); general_layout->addWidget(use_software_fallbacks_checkbox, row, 0, 1, 4); + row++; + + // General -> Default Sequence Settings + QPushButton* default_sequence_settings = new QPushButton(tr("Default Sequence Settings")); + general_layout->addWidget(default_sequence_settings); + tabWidget->addTab(general_tab, tr("General")); // Behavior diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h index e192a9a63..d93ff5ab3 100644 --- a/dialogs/preferencesdialog.h +++ b/dialogs/preferencesdialog.h @@ -34,6 +34,8 @@ #include #include +#include "timeline/sequence.h" + class KeySequenceEditor : public QKeySequenceEdit { Q_OBJECT public: @@ -72,6 +74,13 @@ private: // used to delete previews // type can be: 't' for thumbnails, 'w' for waveforms, or 1 for all + /** + * @brief Delete disk cached preview files (thumbnails, waveforms, etc.) + * + * @param type + * + * The types of previews to + */ void delete_previews(char type); QLineEdit* custom_css_fn; @@ -94,6 +103,7 @@ private: QSpinBox* waveform_res_spinbox; QCheckBox* add_default_effects_to_clips; QComboBox* ui_style; + Sequence sequence_settings; QVector key_shortcut_actions; QVector key_shortcut_items; diff --git a/dialogs/replaceclipmediadialog.cpp b/dialogs/replaceclipmediadialog.cpp index bb8b73b33..a8aec4cfd 100644 --- a/dialogs/replaceclipmediadialog.cpp +++ b/dialogs/replaceclipmediadialog.cpp @@ -20,16 +20,16 @@ #include "replaceclipmediadialog.h" -#include "panels/panels.h" - -#include "rendering/cacher.h" -#include "undo/undo.h" - #include #include #include #include +#include "panels/panels.h" +#include "undo/undostack.h" +#include "rendering/cacher.h" +#include "undo/undo.h" + ReplaceClipMediaDialog::ReplaceClipMediaDialog(QWidget *parent, Media* old_media) : QDialog(parent), media(old_media) diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index b7727e048..c0a08d652 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -32,6 +32,7 @@ #include "panels/panels.h" #include "panels/timeline.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "effects/effect.h" #include "project/media.h" diff --git a/effects/effect.cpp b/effects/effect.cpp index 6197f7601..9b6df1ede 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -20,6 +20,19 @@ #include "effect.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "panels/panels.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" @@ -39,6 +52,7 @@ #include "project/clipboard.h" #include "global/config.h" #include "transition.h" +#include "undo/undostack.h" #include "effects/internal/transformeffect.h" #include "effects/internal/texteffect.h" @@ -54,19 +68,6 @@ #include "effects/internal/fillleftrighteffect.h" #include "effects/internal/frei0reffect.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - QVector effects; EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { @@ -295,7 +296,7 @@ Effect::Effect(Clip* c, const EffectMeta *em) : } } } else if (reader.name() == "shader" && reader.isStartElement()) { - SetFlags(Flags() & ShaderFlag); + SetFlags(Flags() | ShaderFlag); const QXmlStreamAttributes& attributes = reader.attributes(); for (int i=0;i(x_field1->ui_element)->set_previous_value(); - if (y_field1 != nullptr) static_cast(y_field1->ui_element)->set_previous_value(); - if (x_field2 != nullptr) static_cast(x_field2->ui_element)->set_previous_value(); - if (y_field2 != nullptr) static_cast(y_field2->ui_element)->set_previous_value(); - */ -} - int EffectGizmo::get_point_count() { return world_pos.size(); } diff --git a/effects/effectgizmo.h b/effects/effectgizmo.h index 4fa854107..30332b21d 100644 --- a/effects/effectgizmo.h +++ b/effects/effectgizmo.h @@ -57,8 +57,6 @@ public: DoubleField* y_field2; double y_field_multi2; - void set_previous_value(); - QColor color; int get_point_count(); diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index bda3a1a76..713222927 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -25,6 +25,7 @@ #include #include "undo/undo.h" +#include "undo/undostack.h" #include "timeline/clip.h" #include "timeline/sequence.h" #include "panels/panels.h" diff --git a/effects/internal/cornerpineffect.cpp b/effects/internal/cornerpineffect.cpp index a80a504ef..db802503b 100644 --- a/effects/internal/cornerpineffect.cpp +++ b/effects/internal/cornerpineffect.cpp @@ -25,7 +25,7 @@ #include "global/debug.h" CornerPinEffect::CornerPinEffect(Clip* c, const EffectMeta *em) : Effect(c, em) { - SetFlags(Effect::CoordsFlag & Effect::ShaderFlag); + SetFlags(Effect::CoordsFlag | Effect::ShaderFlag); EffectRow* top_left = new EffectRow(this, tr("Top Left")); top_left_x = new DoubleField(top_left, "topleftx"); diff --git a/effects/keyframe.cpp b/effects/keyframe.cpp index c7518477b..d73518cc3 100644 --- a/effects/keyframe.cpp +++ b/effects/keyframe.cpp @@ -24,6 +24,7 @@ #include "effectfields.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "panels/panels.h" EffectKeyframe::EffectKeyframe() diff --git a/global/global.cpp b/global/global.cpp index 9df7c5143..bdc5d08e0 100644 --- a/global/global.cpp +++ b/global/global.cpp @@ -20,15 +20,16 @@ #include "global/global.h" +#include +#include +#include +#include +#include #include "panels/panels.h" - #include "global/path.h" #include "global/config.h" - - #include "rendering/audio.h" - #include "dialogs/demonotice.h" #include "dialogs/preferencesdialog.h" #include "dialogs/exportdialog.h" @@ -36,18 +37,11 @@ #include "dialogs/aboutdialog.h" #include "dialogs/speeddialog.h" #include "dialogs/actionsearch.h" - #include "timeline/sequence.h" - #include "ui/mediaiconservice.h" #include "ui/mainwindow.h" #include "ui/updatenotification.h" - -#include -#include -#include -#include -#include +#include "undo/undostack.h" std::unique_ptr olive::Global; QString olive::ActiveProjectFilename; @@ -56,9 +50,12 @@ QString olive::AppName; OliveGlobal::OliveGlobal() { // sets current app name QString version_id; + + // if available, append the current Git hash (defined by `qmake` and the Makefile) #ifdef GITHASH version_id = QString(" | %1").arg(GITHASH); #endif + olive::AppName = QString("Olive (March 2019 | Alpha%1)").arg(version_id); // set the file filter used in all file dialogs pertaining to Olive project files. @@ -146,6 +143,9 @@ void OliveGlobal::load_translation_from_config() { void OliveGlobal::new_project() { if (can_close_project()) { + // clear graph editor + panel_graph_editor->set_row(nullptr); + // clear effects panel panel_effect_controls->Clear(true); @@ -288,6 +288,7 @@ void OliveGlobal::open_preferences() { void OliveGlobal::set_sequence(SequencePtr s) { + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); olive::ActiveSequence = s; diff --git a/olive.pro b/olive.pro index 59319e67c..0ea4d7149 100644 --- a/olive.pro +++ b/olive.pro @@ -171,7 +171,8 @@ SOURCES += \ effects/fields/buttonfield.cpp \ ui/effectui.cpp \ effects/transition.cpp \ - ui/styling.cpp + ui/styling.cpp \ + undo/undostack.cpp HEADERS += \ ui/mainwindow.h \ @@ -296,7 +297,8 @@ HEADERS += \ effects/fields/colorfield.h \ effects/fields/combofield.h \ effects/transition.h \ - ui/styling.h + ui/styling.h \ + undo/undostack.h FORMS += diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index dacdd7322..dcc83bfbf 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -39,6 +39,7 @@ #include "ui/collapsiblewidget.h" #include "timeline/sequence.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "panels/project.h" #include "panels/timeline.h" #include "panels/viewer.h" diff --git a/panels/project.cpp b/panels/project.cpp index a609c5147..e5c3fbaa0 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -25,6 +25,7 @@ #include "rendering/renderfunctions.h" #include "project/previewgenerator.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "ui/mainwindow.h" #include "global/config.h" #include "rendering/cacher.h" @@ -606,7 +607,9 @@ void Project::delete_selected_media() { // remove if (remove) { + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); + if (olive::ActiveSequence != nullptr) olive::ActiveSequence->selections.clear(); // remove media and parents @@ -1015,6 +1018,9 @@ void Project::delete_clips_using_selected_media() { } void Project::clear() { + // clear graph editor + panel_graph_editor->set_row(nullptr); + // clear effects cache panel_effect_controls->Clear(true); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 06d41798b..9a3732db1 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -37,6 +37,7 @@ #include "ui/flowlayout.h" #include "ui/cursors.h" #include "ui/mainwindow.h" +#include "undo/undostack.h" #include "global/debug.h" #include @@ -450,6 +451,7 @@ void Timeline::nest() { create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list); add_clips_from_ghosts(ca, olive::ActiveSequence.get()); + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); olive::ActiveSequence->selections.clear(); @@ -680,6 +682,7 @@ void Timeline::toggle_enable_on_selected_clips() { void Timeline::delete_selection(QVector& selections, bool ripple_delete) { if (selections.size() > 0) { + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); ComboAction* ca = new ComboAction(); @@ -1014,6 +1017,8 @@ bool selection_contains_transition(const Selection& s, Clip* c, int type) { void Timeline::delete_areas_and_relink(ComboAction* ca, QVector& areas, bool deselect_areas) { clean_up_selections(areas); + + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); QVector pre_clips; diff --git a/panels/viewer.cpp b/panels/viewer.cpp index e31e0cbea..9b1685bb5 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -31,6 +31,7 @@ #include "project/footage.h" #include "project/media.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "ui/audiomonitor.h" #include "rendering/renderfunctions.h" #include "ui/viewercontainer.h" @@ -852,9 +853,13 @@ void Viewer::clean_created_seq() { if (created_sequence) { // TODO delete undo commands referencing this sequence to avoid crashes - /*for (int i=0;i +#include +#include +#include +#include +#include +#include + #include "ui/menuhelper.h" #include "panels/panels.h" #include "project/media.h" @@ -36,15 +44,7 @@ #include "ui/viewerwidget.h" #include "project/proxygenerator.h" #include "ui/mainwindow.h" - -#include -#include -#include -#include -#include -#include - -#include +#include "undo/undostack.h" SourcesCommon::SourcesCommon(Project* parent) : editing_item(nullptr), diff --git a/timeline/marker.cpp b/timeline/marker.cpp index a05985741..afcf495a2 100644 --- a/timeline/marker.cpp +++ b/timeline/marker.cpp @@ -22,6 +22,7 @@ #include "global/config.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "ui/mainwindow.h" #include "timeline/sequence.h" #include "timeline/clip.h" @@ -59,11 +60,11 @@ void set_marker_internal(Sequence* seq, const QVector& clips) { // if (config.set_name_with_marker) is false (set above), ask for a marker name if (!add_marker) { - QInputDialog d(olive::MainWindow); + QInputDialog d(olive::MainWindow); d.setWindowTitle(QCoreApplication::translate("Marker", "Set Marker")); d.setLabelText(clips.size() > 0 - ? QCoreApplication::translate("Marker", "Set clip marker name:") - : QCoreApplication::translate("Marker", "Set sequence marker name:")); + ? QCoreApplication::translate("Marker", "Set clip marker name:") + : QCoreApplication::translate("Marker", "Set sequence marker name:")); d.setInputMode(QInputDialog::TextInput); add_marker = (d.exec() == QDialog::Accepted); marker_name = d.textValue(); @@ -78,10 +79,10 @@ void set_marker_internal(Sequence* seq, const QVector& clips) { // add a marker action for each clip foreach (int i, clips) { - ClipPtr c = seq->clips.at(i); + ClipPtr c = seq->clips.at(i); ca->append(new AddMarkerAction(&c->get_markers(), - seq->playhead - c->timeline_in() + c->clip_in(), - marker_name)); + seq->playhead - c->timeline_in() + c->clip_in(), + marker_name)); } } else { @@ -110,7 +111,7 @@ void set_marker_internal(Sequence* seq, const QVector& clips) { // push action - olive::UndoStack.push(ca); + olive::UndoStack.push(ca); // redraw UI for new markers update_ui(false); diff --git a/timeline/marker.h b/timeline/marker.h index 285f56773..abbb27e0a 100644 --- a/timeline/marker.h +++ b/timeline/marker.h @@ -31,8 +31,8 @@ class Sequence; using SequencePtr = std::shared_ptr; struct Marker { - long frame; - QString name; + long frame; + QString name; }; void draw_marker(QPainter& p, int x, int y, int bottom, bool selected); diff --git a/timeline/sequence.cpp b/timeline/sequence.cpp index 6cd2967f3..6754ef4da 100644 --- a/timeline/sequence.cpp +++ b/timeline/sequence.cpp @@ -25,12 +25,13 @@ #include "panels/panels.h" #include "global/debug.h" -Sequence::Sequence() { - playhead = 0; - using_workarea = false; - workarea_in = 0; - workarea_out = 0; - wrapper_sequence = false; +Sequence::Sequence() : + playhead(0), + using_workarea(false), + workarea_in(0), + workarea_out(0), + wrapper_sequence(false) +{ } Sequence::~Sequence() {} diff --git a/ui/checkboxex.cpp b/ui/checkboxex.cpp index b42c7159e..0682e8b52 100644 --- a/ui/checkboxex.cpp +++ b/ui/checkboxex.cpp @@ -20,6 +20,7 @@ #include "checkboxex.h" +#include "undo/undostack.h" #include "undo/undo.h" CheckboxEx::CheckboxEx(QWidget* parent) : QCheckBox(parent) { diff --git a/ui/graphview.cpp b/ui/graphview.cpp index 7cade8cda..e955db06a 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -33,6 +33,7 @@ #include "timeline/sequence.h" #include "ui/keyframedrawing.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "effects/effect.h" #include "timeline/clip.h" #include "ui/rectangleselect.h" diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 7e9bff745..55b0d6b18 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -20,6 +20,10 @@ #include "keyframeview.h" +#include +#include +#include + #include "effects/effect.h" #include "ui/collapsiblewidget.h" #include "panels/panels.h" @@ -27,6 +31,7 @@ #include "panels/timeline.h" #include "ui/timelineheader.h" #include "undo/undo.h" +#include "undo/undostack.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" #include "timeline/sequence.h" @@ -38,10 +43,6 @@ #include "effects/keyframe.h" #include "ui/graphview.h" -#include -#include -#include - KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), visible_in(0), diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index c06ec97b2..d70bda49b 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -20,35 +20,6 @@ #include "mainwindow.h" -#include "global/global.h" - -#include "ui/menuhelper.h" - -#include "project/projectelements.h" -#include "timeline/clip.h" - -#include "global/config.h" -#include "global/path.h" -#include "global/debug.h" - -#include "project/proxygenerator.h" -#include "project/projectfilter.h" - -#include "ui/sourcetable.h" -#include "ui/viewerwidget.h" -#include "ui/sourceiconview.h" -#include "ui/timelineheader.h" -#include "ui/icons.h" -#include "ui/cursors.h" -#include "ui/focusfilter.h" - -#include "panels/panels.h" - -#include "dialogs/debugdialog.h" - -#include "rendering/audio.h" -#include "rendering/renderfunctions.h" - #include #include #include @@ -65,7 +36,27 @@ #include #include -Q_DECLARE_METATYPE(ClipPtr); +#include "global/global.h" +#include "ui/menuhelper.h" +#include "project/projectelements.h" +#include "timeline/clip.h" +#include "global/config.h" +#include "global/path.h" +#include "global/debug.h" +#include "project/proxygenerator.h" +#include "project/projectfilter.h" +#include "ui/sourcetable.h" +#include "ui/viewerwidget.h" +#include "ui/sourceiconview.h" +#include "ui/timelineheader.h" +#include "ui/icons.h" +#include "ui/cursors.h" +#include "ui/focusfilter.h" +#include "panels/panels.h" +#include "dialogs/debugdialog.h" +#include "rendering/audio.h" +#include "rendering/renderfunctions.h" +#include "undo/undostack.h" MainWindow* olive::MainWindow; @@ -982,6 +973,7 @@ void MainWindow::closeEvent(QCloseEvent *e) { // stop proxy generator thread olive::proxy_generator.cancel(); + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); olive::Global->set_sequence(nullptr); diff --git a/ui/menuhelper.cpp b/ui/menuhelper.cpp index 859f5e493..5aea11144 100644 --- a/ui/menuhelper.cpp +++ b/ui/menuhelper.cpp @@ -122,15 +122,21 @@ void MenuHelper::make_clip_functions_menu(QMenu *parent) { parent->addAction(nest_); } -void MenuHelper::make_edit_functions_menu(QMenu *parent) { - parent->addAction(cut_); - parent->addAction(copy_); +void MenuHelper::make_edit_functions_menu(QMenu *parent, bool objects_are_selected) { + if (objects_are_selected) { + parent->addAction(cut_); + parent->addAction(copy_); + } + parent->addAction(paste_); parent->addAction(paste_insert_); - parent->addAction(duplicate_); - parent->addAction(delete_); - parent->addAction(ripple_delete_); - parent->addAction(split_); + + if (objects_are_selected) { + parent->addAction(duplicate_); + parent->addAction(delete_); + parent->addAction(ripple_delete_); + parent->addAction(split_); + } } void MenuHelper::set_bool_action_checked(QAction *a) { diff --git a/ui/menuhelper.h b/ui/menuhelper.h index e1a14d0d9..9e1783b3e 100644 --- a/ui/menuhelper.h +++ b/ui/menuhelper.h @@ -75,8 +75,13 @@ public: * @param parent * * The menu to add items to. + * + * @param objects_are_selected + * + * Some extra functions may be hidden in the event no clip is actually selected. Set this to **FALSE** to hide those + * functions. */ - void make_edit_functions_menu(QMenu* parent); + void make_edit_functions_menu(QMenu* parent, bool objects_are_selected = true); /** * @brief Sets the checked state of a menu item based on a Boolean variable. diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index de9e71902..c95b56e4c 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -20,6 +20,13 @@ #include "timelineheader.h" +#include +#include +#include +#include +#include +#include + #include "mainwindow.h" #include "panels/panels.h" #include "panels/timeline.h" @@ -31,13 +38,7 @@ #include "global/global.h" #include "ui/menuhelper.h" #include "global/debug.h" - -#include -#include -#include -#include -#include -#include +#include "undo/undostack.h" #define CLICK_RANGE 5 #define PLAYHEAD_SIZE 6 diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index af6f142c8..8087085d3 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -20,32 +20,6 @@ #include "timelinewidget.h" -#include "global/global.h" -#include "panels/panels.h" -#include "project/projectelements.h" - -#include "rendering/audio.h" -#include "global/config.h" -#include "ui/sourcetable.h" -#include "ui/sourceiconview.h" -#include "undo/undo.h" -#include "ui/viewerwidget.h" -#include "ui/resizablescrollbar.h" -#include "dialogs/newsequencedialog.h" -#include "mainwindow.h" -#include "ui/rectangleselect.h" -#include "rendering/renderfunctions.h" -#include "ui/cursors.h" -#include "ui/menuhelper.h" -#include "ui/focusfilter.h" -#include "dialogs/clippropertiesdialog.h" -#include "global/debug.h" - -#include "effects/effect.h" - -#include "effects/internal/solideffect.h" -#include "effects/internal/texteffect.h" - #include #include #include @@ -61,6 +35,30 @@ #include #include +#include "global/global.h" +#include "panels/panels.h" +#include "project/projectelements.h" +#include "rendering/audio.h" +#include "global/config.h" +#include "ui/sourcetable.h" +#include "ui/sourceiconview.h" +#include "undo/undo.h" +#include "undo/undostack.h" +#include "ui/viewerwidget.h" +#include "ui/resizablescrollbar.h" +#include "dialogs/newsequencedialog.h" +#include "mainwindow.h" +#include "ui/rectangleselect.h" +#include "rendering/renderfunctions.h" +#include "ui/cursors.h" +#include "ui/menuhelper.h" +#include "ui/focusfilter.h" +#include "dialogs/clippropertiesdialog.h" +#include "global/debug.h" +#include "effects/effect.h" +#include "effects/internal/solideffect.h" +#include "effects/internal/texteffect.h" + #define MAX_TEXT_WIDTH 20 #define TRANSITION_BETWEEN_RANGE 40 @@ -90,8 +88,6 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { QMenu menu(this); - // TODO replace with Olive::MenuHelper::make_edit_functions_menu() without losing functionality - QAction* undoAction = menu.addAction(tr("&Undo")); QAction* redoAction = menu.addAction(tr("&Redo")); connect(undoAction, SIGNAL(triggered(bool)), olive::Global.get(), SLOT(undo())); @@ -103,13 +99,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { // collect all the selected clips QVector selected_clips = olive::ActiveSequence->SelectedClips(); - if (!selected_clips.isEmpty()) { - // clips are selected - menu.addAction(tr("C&ut"), &olive::FocusFilter, SLOT(cut())); - menu.addAction(tr("Cop&y"), &olive::FocusFilter, SLOT(copy())); - } - - menu.addAction(tr("&Paste"), olive::Global.get(), SLOT(paste())); + olive::MenuHelper.make_edit_functions_menu(&menu, !selected_clips.isEmpty()); if (selected_clips.isEmpty()) { // no clips are selected @@ -119,7 +109,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { panel_timeline->cursor_track = getTrackFromScreenPoint(pos.y()); if (panel_timeline->can_ripple_empty_space(panel_timeline->cursor_frame, panel_timeline->cursor_track)) { - QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete")); + QAction* ripple_delete_action = menu.addAction(tr("R&ipple Delete Empty Space")); connect(ripple_delete_action, SIGNAL(triggered(bool)), panel_timeline, SLOT(ripple_delete_empty_space())); } @@ -128,7 +118,9 @@ void TimelineWidget::show_context_menu(const QPoint& pos) { } if (!selected_clips.isEmpty()) { + menu.addSeparator(); + menu.addAction(tr("&Speed/Duration"), olive::Global.get(), SLOT(open_speed_dialog())); QAction* autoscaleAction = menu.addAction(tr("Auto-s&cale"), this, SLOT(toggle_autoscale())); @@ -277,9 +269,10 @@ void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { panel_project->process_file_list(file_list); for (int i=0;ilast_imported_media.size();i++) { + Footage* f = panel_project->last_imported_media.at(i)->to_footage(); + // waits for media to have a duration // TODO would be much nicer if this was multithreaded - Footage* f = panel_project->last_imported_media.at(i)->to_footage(); f->ready_lock.lock(); f->ready_lock.unlock(); diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 37a24d540..cfeceb1f2 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -326,10 +326,6 @@ void ViewerWidget::mousePressEvent(QMouseEvent* event) { gizmo_y_mvmt = 0; selected_gizmo = get_gizmo_from_mouse(event->pos().x(), event->pos().y()); - - if (selected_gizmo != nullptr) { - selected_gizmo->set_previous_value(); - } } dragging = true; } diff --git a/undo/undo.cpp b/undo/undo.cpp index 23d3429bc..172755afb 100644 --- a/undo/undo.cpp +++ b/undo/undo.cpp @@ -42,8 +42,6 @@ #include "project/previewgenerator.h" #include "ui/mainwindow.h" -QUndoStack olive::UndoStack; - MoveClipAction::MoveClipAction(Clip *c, long iin, long iout, long iclip_in, int itrack, bool irelative) { clip = c; @@ -354,6 +352,7 @@ AddClipCommand::~AddClipCommand() {} void AddClipCommand::doUndo() { // clear effects panel + panel_graph_editor->set_row(nullptr); panel_effect_controls->Clear(true); for (int i=0;iupdate_tooltip(); for (int i=0;iclips.size();i++) { - if (seq->clips.at(i) != nullptr) seq->clips.at(i)->refresh(); + if (seq->clips.at(i) != nullptr) { + seq->clips.at(i)->refresh(); + } } if (olive::ActiveSequence == seq) { diff --git a/undo/undo.h b/undo/undo.h index 11853f818..d55ed478d 100644 --- a/undo/undo.h +++ b/undo/undo.h @@ -53,10 +53,6 @@ struct EffectMeta; class EffectRow; class EffectField; -namespace olive { -extern QUndoStack UndoStack; -} - class OliveAction : public QUndoCommand { public: OliveAction(bool iset_window_modified = true); diff --git a/undo/undostack.cpp b/undo/undostack.cpp new file mode 100644 index 000000000..2edc0f0b1 --- /dev/null +++ b/undo/undostack.cpp @@ -0,0 +1,3 @@ +#include "undostack.h" + +QUndoStack olive::UndoStack; diff --git a/undo/undostack.h b/undo/undostack.h new file mode 100644 index 000000000..72086a823 --- /dev/null +++ b/undo/undostack.h @@ -0,0 +1,10 @@ +#ifndef UNDOSTACK_H +#define UNDOSTACK_H + +#include + +namespace olive { +extern QUndoStack UndoStack; +} + +#endif // UNDOSTACK_H From 53334b539937d3517aaeaa750139720d219126f0 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 19:25:53 +1100 Subject: [PATCH 34/56] some finishing touches --- effects/effect.cpp | 5 ++--- effects/effectfield.cpp | 2 ++ effects/fields/boolfield.cpp | 2 ++ effects/fields/combofield.cpp | 2 ++ effects/fields/combofield.h | 2 +- effects/fields/doublefield.cpp | 1 + effects/fields/stringfield.cpp | 1 + effects/internal/solideffect.cpp | 6 ++++-- effects/internal/solideffect.h | 2 +- effects/internal/transformeffect.h | 2 +- 10 files changed, 17 insertions(+), 8 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index 9b6df1ede..81cdd83d5 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -540,15 +540,13 @@ void Effect::load(QXmlStreamReader& stream) { EffectField* field = row->Field(field_number); // get current field value - /* for (int k=0;kSetCurrentValue(field->GetValueFromString(attr.value().toString())); + field->persistent_data_ = field->ConvertStringToValue(attr.value().toString()); break; } } - */ while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { stream.readNext(); @@ -609,6 +607,7 @@ void Effect::save(QXmlStreamWriter& stream) { if (!field->id().isEmpty()) { stream.writeStartElement("field"); // field stream.writeAttribute("id", field->id()); + stream.writeAttribute("value", field->ConvertValueToString(field->persistent_data_)); for (int k=0;kkeyframes.size();k++) { const EffectKeyframe& key = field->keyframes.at(k); stream.writeStartElement("key"); diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index 23c863060..3afec20c0 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -241,7 +241,9 @@ void EffectField::SetValueAt(double time, const QVariant &value) } } else { + persistent_data_ = value; + } emit Changed(); diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp index 9c23d9202..33102544d 100644 --- a/effects/fields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -34,6 +34,8 @@ void BoolField::UpdateWidgetValue(QWidget *widget, double timecode) cb->setChecked(GetBoolAt(timecode)); cb->blockSignals(false); + + emit Toggled(cb->isChecked()); } QVariant BoolField::ConvertStringToValue(const QString &s) diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp index 6b1a46e3f..828705f67 100644 --- a/effects/fields/combofield.cpp +++ b/effects/fields/combofield.cpp @@ -45,6 +45,8 @@ void ComboField::UpdateWidgetValue(QWidget *widget, double timecode) cb->blockSignals(true); cb->setCurrentIndex(i); cb->blockSignals(false); + + emit DataChanged(data); return; } } diff --git a/effects/fields/combofield.h b/effects/fields/combofield.h index 97fe2efd7..d9c81e60a 100644 --- a/effects/fields/combofield.h +++ b/effects/fields/combofield.h @@ -20,7 +20,7 @@ public: virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; signals: - void IndexChanged(int i); + void DataChanged(const QVariant&); private: QVector items_; diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 42c58488b..378d18879 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -74,6 +74,7 @@ QWidget *DoubleField::CreateWidget() ls->SetDisplayType(display_type_); ls->SetFrameRate(frame_rate_); + //qDebug() << ""; ls->setEnabled(IsEnabled()); connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double))); diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 777a0fdfc..3b3d7579a 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -1,6 +1,7 @@ #include "stringfield.h" #include +#include #include "ui/texteditex.h" #include "global/config.h" diff --git a/effects/internal/solideffect.cpp b/effects/internal/solideffect.cpp index 7dd6c5cc3..db6f7434c 100644 --- a/effects/internal/solideffect.cpp +++ b/effects/internal/solideffect.cpp @@ -61,7 +61,7 @@ SolidEffect::SolidEffect(Clip* c, const EffectMeta* em) : checkerboard_size_field->SetMinimum(1); checkerboard_size_field->SetDefault(10); - connect(solid_type, SIGNAL(IndexChanged(int)), this, SLOT(ui_update(int))); + connect(solid_type, SIGNAL(DataChanged(const QVariant&)), this, SLOT(ui_update(const QVariant&))); // Set default UI solid_type->SetValueAt(0, SOLID_TYPE_COLOR); @@ -202,7 +202,9 @@ void SolidEffect::SetType(SolidEffect::SolidType type) solid_type->SetValueAt(0, type); } -void SolidEffect::ui_update(int i) { +void SolidEffect::ui_update(const QVariant& d) { + int i = d.toInt(); + solid_color_field->SetEnabled(i == SOLID_TYPE_COLOR || i == SOLID_TYPE_CHECKERBOARD); checkerboard_size_field->SetEnabled(i == SOLID_TYPE_CHECKERBOARD); } diff --git a/effects/internal/solideffect.h b/effects/internal/solideffect.h index 3d099b17f..26843fe71 100644 --- a/effects/internal/solideffect.h +++ b/effects/internal/solideffect.h @@ -39,7 +39,7 @@ public: void SetType(SolidType type); private slots: - void ui_update(int); + void ui_update(const QVariant &d); private: ComboField* solid_type; ColorField* solid_color_field; diff --git a/effects/internal/transformeffect.h b/effects/internal/transformeffect.h index 84f64fadb..43aad2b26 100644 --- a/effects/internal/transformeffect.h +++ b/effects/internal/transformeffect.h @@ -26,7 +26,7 @@ class TransformEffect : public Effect { Q_OBJECT public: - TransformEffect(Clip* c, const EffectMeta* em); + TransformEffect(Clip* c, const EffectMeta* em); void refresh(); void process_coords(double timecode, GLTextureCoords& coords, int data); From bda0fdf37643af7e2d736701d2aaf11b201fa4e8 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 19:48:05 +1100 Subject: [PATCH 35/56] don't scroll sides when using hand tool --- ui/timelinewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 8087085d3..01252a49f 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -2000,7 +2000,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { panel_timeline->cursor_track = getTrackFromScreenPoint(event->pos().y()); // if holding the mouse button down, let's scroll to that location - if (event->buttons() != 0) { + if (event->buttons() != 0 && panel_timeline->tool != TIMELINE_TOOL_HAND) { panel_timeline->scroll_to_frame(panel_timeline->cursor_frame); } From 36c6415a9a3c22e3d4ae6d6b2d55091a7c179406 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 19:48:13 +1100 Subject: [PATCH 36/56] fixed text effect crash --- effects/fields/stringfield.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 3b3d7579a..257aa2fb5 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -37,7 +37,15 @@ QWidget *StringField::CreateWidget() void StringField::UpdateWidgetValue(QWidget *widget, double timecode) { - static_cast(widget)->setHtml(GetValueAt(timecode).toString()); + TextEditEx* text = static_cast(widget); + + text->blockSignals(true); + + QTextCursor cursor = text->textCursor(); + text->setHtml(GetValueAt(timecode).toString()); + text->setTextCursor(cursor); + + text->blockSignals(false); } void StringField::UpdateFromWidget(const QString &s) From 8f923d9d929e851fa1d4e82965f61a4d305ace0e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 19:57:47 +1100 Subject: [PATCH 37/56] keep text cursor position on stringfield --- effects/fields/stringfield.cpp | 8 ++++++-- effects/internal/texteffect.cpp | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 257aa2fb5..35c58f2a1 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -41,9 +41,13 @@ void StringField::UpdateWidgetValue(QWidget *widget, double timecode) text->blockSignals(true); - QTextCursor cursor = text->textCursor(); + int pos = text->textCursor().position(); + text->setHtml(GetValueAt(timecode).toString()); - text->setTextCursor(cursor); + + QTextCursor new_cursor(text->document()); + new_cursor.setPosition(pos); + text->setTextCursor(new_cursor); text->blockSignals(false); } diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index 4c51f47e4..41a0630c1 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -123,6 +123,7 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : size_val->SetDefault(48); text_val->SetValueAt(0, tr("Sample Text")); + set_color_button->SetValueAt(0, QColor(Qt::white)); halign_field->SetValueAt(0, Qt::AlignHCenter); valign_field->SetValueAt(0, Qt::AlignVCenter); word_wrap_field->SetValueAt(0, true); From a3831bbd50d6c601c0fa7ef87a100cc79303d989 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 20:38:28 +1100 Subject: [PATCH 38/56] made improvements to legacy text effect --- dialogs/texteditdialog.cpp | 62 +++++++++++++++++++++-------- dialogs/texteditdialog.h | 11 ++++- effects/internal/richtexteffect.cpp | 20 ++++++++++ effects/internal/richtexteffect.h | 15 +++++++ effects/internal/texteffect.cpp | 15 ++++++- effects/internal/texteffect.h | 14 ++++--- icons/icons.qrc | 2 + icons/italic.svg | 3 ++ icons/underline.svg | 3 ++ olive.pro | 6 ++- ui/texteditex.cpp | 16 ++++++-- ui/texteditex.h | 4 +- 12 files changed, 139 insertions(+), 32 deletions(-) create mode 100644 effects/internal/richtexteffect.cpp create mode 100644 effects/internal/richtexteffect.h create mode 100644 icons/italic.svg create mode 100644 icons/underline.svg diff --git a/dialogs/texteditdialog.cpp b/dialogs/texteditdialog.cpp index de9328209..69cd149f4 100644 --- a/dialogs/texteditdialog.cpp +++ b/dialogs/texteditdialog.cpp @@ -23,35 +23,56 @@ #include #include #include +#include -TextEditDialog::TextEditDialog(QWidget *parent, const QString &s) : - QDialog(parent) +#include "ui/icons.h" + +TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text) : + QDialog(parent), + rich_text_(rich_text) { setWindowTitle(tr("Edit Text")); QVBoxLayout* layout = new QVBoxLayout(this); - QHBoxLayout* toolbar = new QHBoxLayout(); + if (rich_text) { + QHBoxLayout* toolbar = new QHBoxLayout(); - QPushButton* italic_button = new QPushButton("I"); - italic_button->setCheckable(true); - toolbar->addWidget(italic_button); + // Italic Button + italic_button = new QPushButton(); + italic_button->setIcon(QIcon(":/icons/italic.svg")); + italic_button->setCheckable(true); + connect(italic_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontItalic(bool))); + toolbar->addWidget(italic_button); - QPushButton* underline_button = new QPushButton("U"); - underline_button->setCheckable(true); - toolbar->addWidget(underline_button); + // Underline Button + underline_button = new QPushButton(); + underline_button->setIcon(QIcon(":/icons/underline.svg")); + underline_button->setCheckable(true); + toolbar->addWidget(underline_button); - toolbar->addStretch(); + // Font Name + font_list = new QFontComboBox(); + connect(font_list, SIGNAL(setCurrentFont(const QFont&)), textEdit, SLOT(setCurrentFont(const QFont&))); + toolbar->addWidget(font_list); - layout->addLayout(toolbar); + toolbar->addStretch(); + + layout->addLayout(toolbar); + } + + // Create central text editor object textEdit = new QTextEdit(this); - textEdit->setHtml(s); - layout->addWidget(textEdit); + textEdit->setUndoRedoEnabled(true); - // Connect buttons to the text field - connect(italic_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontItalic(bool))); - connect(underline_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontUnderline(bool))); + if (rich_text_) { + textEdit->setHtml(s); + } else { + textEdit->setPlainText(s); + } + + layout->addWidget(textEdit); // Create dialog buttons at the bottom QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); @@ -65,10 +86,17 @@ const QString& TextEditDialog::get_string() { } void TextEditDialog::save() { - result_str = textEdit->toHtml(); + result_str = rich_text_ ? textEdit->toHtml() : textEdit->toPlainText(); accept(); } void TextEditDialog::cancel() { reject(); } + +void TextEditDialog::UpdateUIFromTextCursor() +{ + italic_button->setChecked(textEdit->fontItalic()); + underline_button->setChecked(textEdit->fontUnderline()); + font_list->setCurrentText(textEdit->fontFamily()); +} diff --git a/dialogs/texteditdialog.h b/dialogs/texteditdialog.h index 28a682d90..12f342b61 100644 --- a/dialogs/texteditdialog.h +++ b/dialogs/texteditdialog.h @@ -23,18 +23,27 @@ #include #include +#include class TextEditDialog : public QDialog { Q_OBJECT public: - TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr); + TextEditDialog(QWidget* parent = nullptr, const QString& s = nullptr, bool rich_text = true); const QString& get_string(); +signals: + void cursorPositionChanged(); private slots: void save(); void cancel(); + void UpdateUIFromTextCursor(); private: + bool rich_text_; + QString result_str; QTextEdit* textEdit; + QPushButton* italic_button; + QPushButton* underline_button; + QFontComboBox* font_list; }; #endif // TEXTEDITDIALOG_H diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp new file mode 100644 index 000000000..271799156 --- /dev/null +++ b/effects/internal/richtexteffect.cpp @@ -0,0 +1,20 @@ +#include "richtexteffect.h" + +RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) +{ + +} + +void RichTextEffect::redraw(double timecode) +{ + QPainter p(&img); + p.setRenderHint(QPainter::Antialiasing); + int width = img.width(); + int height = img.height(); + + img.fill(Qt::transparent); + + QTextDocument td; + td.setHtml(text_val->GetStringAt(timecode)); + td.drawContents(&p); +} diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h new file mode 100644 index 000000000..7bd0bd214 --- /dev/null +++ b/effects/internal/richtexteffect.h @@ -0,0 +1,15 @@ +#ifndef RICHTEXTEFFECT_H +#define RICHTEXTEFFECT_H + +#include "effects/effect.h" + +class RichTextEffect : public Effect { + Q_OBJECT +public: + RichTextEffect(Clip* c, const EffectMeta *em); + void redraw(double timecode); + + StringField* text_val; +}; + +#endif // RICHTEXTEFFECT_H diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index 41a0630c1..5f562181b 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -80,6 +80,14 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : word_wrap_field = new BoolField(word_wrap_row, "wordwrap"); word_wrap_field->SetColumnSpan(2); + EffectRow* padding_row = new EffectRow(this, tr("Padding")); + padding_field = new DoubleField(padding_row, "padding"); + padding_field->SetColumnSpan(2); + + EffectRow* position_row = new EffectRow(this, tr("Position")); + position_x = new DoubleField(position_row, "posx"); + position_y = new DoubleField(position_row, "posy"); + EffectRow* outline_row = new EffectRow(this, tr("Outline")); outline_bool = new BoolField(outline_row, "outline"); outline_bool->SetColumnSpan(2); @@ -217,8 +225,9 @@ void TextEffect::redraw(double timecode) { QPainter p(&img); p.setRenderHint(QPainter::Antialiasing); - int width = img.width(); - int height = img.height(); + int padding = qRound(padding_field->GetDoubleAt(timecode)); + int width = img.width() - padding * 2; + int height = img.height() - padding * 2; // set font font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias); @@ -307,6 +316,8 @@ void TextEffect::redraw(double timecode) { path.addText(text_x, text_y, font, lines.at(i)); } + path.translate(position_x->GetDoubleAt(timecode) + padding, position_y->GetDoubleAt(timecode) + padding); + // draw software shadow if (shadow_bool->GetBoolAt(timecode)) { p.setPen(Qt::NoPen); diff --git a/effects/internal/texteffect.h b/effects/internal/texteffect.h index b74356dbf..05b9286a8 100644 --- a/effects/internal/texteffect.h +++ b/effects/internal/texteffect.h @@ -31,6 +31,11 @@ class TextEffect : public Effect { public: TextEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); +private slots: + void outline_enable(bool); + void shadow_enable(bool); +private: + QFont font; StringField* text_val; DoubleField* size_val; @@ -39,6 +44,9 @@ public: ComboField* halign_field; ComboField* valign_field; BoolField* word_wrap_field; + DoubleField* padding_field; + DoubleField* position_x; + DoubleField* position_y; BoolField* outline_bool; DoubleField* outline_width; @@ -50,11 +58,7 @@ public: ColorField* shadow_color; DoubleField* shadow_softness; DoubleField* shadow_opacity; -private slots: - void outline_enable(bool); - void shadow_enable(bool); -private: - QFont font; + }; #endif // TEXTEFFECT_H diff --git a/icons/icons.qrc b/icons/icons.qrc index b4ccfa3b2..d6e6f33b8 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -45,5 +45,7 @@ videosource.svg zoomin.svg zoomout.svg + italic.svg + underline.svg diff --git a/icons/italic.svg b/icons/italic.svg new file mode 100644 index 000000000..facb40395 --- /dev/null +++ b/icons/italic.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/icons/underline.svg b/icons/underline.svg new file mode 100644 index 000000000..a6f80735b --- /dev/null +++ b/icons/underline.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/olive.pro b/olive.pro index 0ea4d7149..ccf476442 100644 --- a/olive.pro +++ b/olive.pro @@ -172,7 +172,8 @@ SOURCES += \ ui/effectui.cpp \ effects/transition.cpp \ ui/styling.cpp \ - undo/undostack.cpp + undo/undostack.cpp \ + effects/internal/richtexteffect.cpp HEADERS += \ ui/mainwindow.h \ @@ -298,7 +299,8 @@ HEADERS += \ effects/fields/combofield.h \ effects/transition.h \ ui/styling.h \ - undo/undostack.h + undo/undostack.h \ + effects/internal/richtexteffect.h FORMS += diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp index e4c525dd4..49ee64a8c 100644 --- a/ui/texteditex.cpp +++ b/ui/texteditex.cpp @@ -68,7 +68,9 @@ void TextEditEx::updateText() { #include "dialogs/texteditdialog.h" #include "mainwindow.h" -TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) +TextEditEx::TextEditEx(QWidget *parent, bool enable_rich_text) : + QTextEdit(parent), + enable_rich_text_(enable_rich_text) { setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(text_edit_menu())); @@ -85,15 +87,21 @@ void TextEditEx::text_edit_menu() { } void TextEditEx::open_text_edit() { - TextEditDialog ted(olive::MainWindow, this->toHtml()); + const QString& current_text = (enable_rich_text_) ? toHtml() : toPlainText(); + + TextEditDialog ted(olive::MainWindow, current_text, enable_rich_text_); ted.exec(); QString result = ted.get_string(); if (!result.isEmpty()) { - setHtml(result); + if (enable_rich_text_) { + setHtml(result); + } else { + setPlainText(result); + } } } void TextEditEx::queue_text_modified() { - emit textModified(toHtml()); + emit textModified(toPlainText()); } diff --git a/ui/texteditex.h b/ui/texteditex.h index 20d3d08f9..0b4802a30 100644 --- a/ui/texteditex.h +++ b/ui/texteditex.h @@ -26,13 +26,15 @@ class TextEditEx : public QTextEdit { Q_OBJECT public: - TextEditEx(QWidget* parent = nullptr); + TextEditEx(QWidget* parent = nullptr, bool enable_rich_text = true); signals: void textModified(const QString& s); private slots: void text_edit_menu(); void open_text_edit(); void queue_text_modified(); +private: + bool enable_rich_text_; }; #endif // TEXTEDITEX_H From c0d3e038eba5227b2a16ec6b096c318778040556 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 20:50:21 +1100 Subject: [PATCH 39/56] added rich text mode --- effects/effect.cpp | 2 ++ effects/effect.h | 1 + effects/effectloaders.cpp | 5 +++++ effects/fields/stringfield.cpp | 13 +++++++++---- effects/fields/stringfield.h | 4 +++- effects/internal/richtexteffect.cpp | 8 ++++++-- effects/internal/richtexteffect.h | 2 +- effects/internal/texteffect.cpp | 2 +- 8 files changed, 28 insertions(+), 9 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index 81cdd83d5..964487a90 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -67,6 +67,7 @@ #include "effects/internal/vsthost.h" #include "effects/internal/fillleftrighteffect.h" #include "effects/internal/frei0reffect.h" +#include "effects/internal/richtexteffect.h" QVector effects; @@ -91,6 +92,7 @@ EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { #ifndef NOFREI0R case EFFECT_INTERNAL_FREI0R: return std::make_shared(c, em); #endif + case EFFECT_INTERNAL_RICHTEXT: return std::make_shared(c, em); } } else if (!em->filename.isEmpty()) { // load effect from file diff --git a/effects/effect.h b/effects/effect.h index dd0780c5a..4944ad5d4 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -93,6 +93,7 @@ enum EffectInternal { EFFECT_INTERNAL_VST, EFFECT_INTERNAL_CORNERPIN, EFFECT_INTERNAL_FREI0R, + EFFECT_INTERNAL_RICHTEXT, EFFECT_INTERNAL_COUNT }; diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index d00c8b67b..d53390ab5 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -99,6 +99,11 @@ void load_internal_effects() { em.internal = EFFECT_INTERNAL_TEXT; effects.append(em); + em.name = "Rich Text"; + em.category = "Render"; + em.internal = EFFECT_INTERNAL_RICHTEXT; + effects.append(em); + em.name = "Timecode"; em.internal = EFFECT_INTERNAL_TIMECODE; effects.append(em); diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 35c58f2a1..45d7b023c 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -6,8 +6,9 @@ #include "ui/texteditex.h" #include "global/config.h" -StringField::StringField(EffectRow* parent, const QString& id) : - EffectField(parent, id, EFFECT_FIELD_STRING) +StringField::StringField(EffectRow* parent, const QString& id, bool rich_text) : + EffectField(parent, id, EFFECT_FIELD_STRING), + rich_text_(rich_text) { } @@ -19,7 +20,7 @@ QString StringField::GetStringAt(double timecode) QWidget *StringField::CreateWidget() { - TextEditEx* text_edit = new TextEditEx(); + TextEditEx* text_edit = new TextEditEx(nullptr, rich_text_); text_edit->setEnabled(IsEnabled()); text_edit->setUndoRedoEnabled(true); @@ -43,7 +44,11 @@ void StringField::UpdateWidgetValue(QWidget *widget, double timecode) int pos = text->textCursor().position(); - text->setHtml(GetValueAt(timecode).toString()); + if (rich_text_) { + text->setHtml(GetValueAt(timecode).toString()); + } else { + text->setPlainText(GetValueAt(timecode).toString()); + } QTextCursor new_cursor(text->document()); new_cursor.setPosition(pos); diff --git a/effects/fields/stringfield.h b/effects/fields/stringfield.h index 969ce52af..6202afb27 100644 --- a/effects/fields/stringfield.h +++ b/effects/fields/stringfield.h @@ -7,7 +7,7 @@ class StringField : public EffectField { Q_OBJECT public: - StringField(EffectRow* parent, const QString& id); + StringField(EffectRow* parent, const QString& id, bool rich_text = true); QString GetStringAt(double timecode); @@ -15,6 +15,8 @@ public: virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; private slots: void UpdateFromWidget(const QString& b); +private: + bool rich_text_; }; #endif // STRINGFIELD_H diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp index 271799156..30a1f0fef 100644 --- a/effects/internal/richtexteffect.cpp +++ b/effects/internal/richtexteffect.cpp @@ -1,8 +1,12 @@ #include "richtexteffect.h" -RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) -{ +#include +RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : + Effect(c, em) +{ + EffectRow* text_row = new EffectRow(this, tr("Text")); + text_val = new StringField(text_row, "text"); } void RichTextEffect::redraw(double timecode) diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h index 7bd0bd214..37eb50530 100644 --- a/effects/internal/richtexteffect.h +++ b/effects/internal/richtexteffect.h @@ -8,7 +8,7 @@ class RichTextEffect : public Effect { public: RichTextEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); - +private: StringField* text_val; }; diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index 5f562181b..8365a57ce 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -48,7 +48,7 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : SetFlags(Effect::SuperimposeFlag); EffectRow* text_field = new EffectRow(this, tr("Text")); - text_val = new StringField(text_field, "text"); + text_val = new StringField(text_field, "text", false); text_val->SetColumnSpan(2); EffectRow* font_row = new EffectRow(this, tr("Font")); From 9fc542e6886733c22a7bcae53837bd0c72a35dfc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 22:56:23 +1100 Subject: [PATCH 40/56] further progress on rich text effect --- dialogs/texteditdialog.cpp | 153 ++++++++++++++++++++++++++-- dialogs/texteditdialog.h | 15 +++ effects/internal/richtexteffect.cpp | 47 ++++++++- effects/internal/richtexteffect.h | 4 + icons/align-center.svg | 3 + icons/align-left.svg | 3 + icons/align-right.svg | 3 + icons/bold.svg | 3 + icons/icons.qrc | 5 + icons/italic.svg | 2 +- icons/justify-center.svg | 3 + icons/underline.svg | 2 +- ui/keyframenavigator.cpp | 2 + ui/texteditex.cpp | 2 +- 14 files changed, 232 insertions(+), 15 deletions(-) create mode 100644 icons/align-center.svg create mode 100644 icons/align-left.svg create mode 100644 icons/align-right.svg create mode 100644 icons/bold.svg create mode 100644 icons/justify-center.svg diff --git a/dialogs/texteditdialog.cpp b/dialogs/texteditdialog.cpp index 69cd149f4..00e338c3a 100644 --- a/dialogs/texteditdialog.cpp +++ b/dialogs/texteditdialog.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "ui/icons.h" @@ -35,9 +36,23 @@ TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text QVBoxLayout* layout = new QVBoxLayout(this); + // Create central text editor object + textEdit = new QTextEdit(this); + textEdit->setUndoRedoEnabled(true); + + // Upper toolbar if (rich_text) { QHBoxLayout* toolbar = new QHBoxLayout(); + // Bold Button + /* + bold_button = new QPushButton(); + bold_button->setIcon(QIcon(":/icons/bold.svg")); + bold_button->setCheckable(true); + connect(bold_button, SIGNAL(clicked(bool)), this, SLOT(SetBold(bool))); + toolbar->addWidget(bold_button); + */ + // Italic Button italic_button = new QPushButton(); italic_button->setIcon(QIcon(":/icons/italic.svg")); @@ -49,36 +64,109 @@ TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text underline_button = new QPushButton(); underline_button->setIcon(QIcon(":/icons/underline.svg")); underline_button->setCheckable(true); + connect(underline_button, SIGNAL(clicked(bool)), textEdit, SLOT(setFontUnderline(bool))); toolbar->addWidget(underline_button); // Font Name font_list = new QFontComboBox(); - connect(font_list, SIGNAL(setCurrentFont(const QFont&)), textEdit, SLOT(setCurrentFont(const QFont&))); + connect(font_list, SIGNAL(currentIndexChanged(const QString&)), textEdit, SLOT(setFontFamily(const QString&))); toolbar->addWidget(font_list); + // Font Weight + font_weight = new QComboBox(); + font_weight->addItem(tr("Thin"), QFont::Thin); + font_weight->addItem(tr("Extra Light"), QFont::ExtraLight); + font_weight->addItem(tr("Light"), QFont::Light); + font_weight->addItem(tr("Normal"), QFont::Normal); + font_weight->addItem(tr("Medium"), QFont::Medium); + font_weight->addItem(tr("Demi Bold"), QFont::DemiBold); + font_weight->addItem(tr("Bold"), QFont::Bold); + font_weight->addItem(tr("Extra Bold"), QFont::ExtraBold); + font_weight->addItem(tr("Black"), QFont::Black); + connect(font_weight, SIGNAL(currentIndexChanged(int)), this, SLOT(SetFontWeight(int))); + toolbar->addWidget(font_weight); + + // Font Size + font_size = new LabelSlider(); + connect(font_size, SIGNAL(valueChanged(double)), textEdit, SLOT(setFontPointSize(qreal))); + toolbar->addWidget(font_size); + + // Font Color + font_color = new ColorButton(); + connect(font_color, SIGNAL(color_changed(const QColor&)), textEdit, SLOT(setTextColor(const QColor &))); + toolbar->addWidget(font_color); toolbar->addStretch(); + // Left Align + left_align_button = new QPushButton(); + left_align_button->setIcon(QIcon(":/icons/align-left.svg")); + left_align_button->setCheckable(true); + left_align_button->setProperty("a", Qt::AlignLeft); + connect(left_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); + toolbar->addWidget(left_align_button); + + // Center Align + center_align_button = new QPushButton(); + center_align_button->setIcon(QIcon(":/icons/align-center.svg")); + center_align_button->setCheckable(true); + center_align_button->setProperty("a", Qt::AlignCenter); + connect(center_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); + toolbar->addWidget(center_align_button); + + // Right Align + right_align_button = new QPushButton(); + right_align_button->setIcon(QIcon(":/icons/align-right.svg")); + right_align_button->setCheckable(true); + right_align_button->setProperty("a", Qt::AlignRight); + connect(right_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); + toolbar->addWidget(right_align_button); + + // Justify Align + justify_align_button = new QPushButton(); + justify_align_button->setIcon(QIcon(":/icons/justify-center.svg")); + justify_align_button->setCheckable(true); + justify_align_button->setProperty("a", Qt::AlignJustify); + connect(justify_align_button, SIGNAL(clicked(bool)), this, SLOT(SetAlignmentFromProperty())); + toolbar->addWidget(justify_align_button); + layout->addLayout(toolbar); } - // Create central text editor object - textEdit = new QTextEdit(this); - textEdit->setUndoRedoEnabled(true); + layout->addWidget(textEdit); + // Lower toolbar + /* + if (rich_text) { + QHBoxLayout* lower_toolbar = new QHBoxLayout(); + + lower_toolbar->addWidget(new QLabel(tr("Letter Spacing:"))); + + letter_spacing = new LabelSlider(); + connect(letter_spacing, SIGNAL(valueChanged(double)), this, SLOT(SetLetterSpacing(qreal))); + lower_toolbar->addWidget(letter_spacing); + + lower_toolbar->addStretch(); + + layout->addLayout(lower_toolbar); + } + */ + + // Create dialog buttons at the bottom + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + buttons->setCenterButtons(true); + layout->addWidget(buttons); + connect(buttons, SIGNAL(accepted()), this, SLOT(save())); + connect(buttons, SIGNAL(rejected()), this, SLOT(cancel())); + + connect(textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(UpdateUIFromTextCursor())); if (rich_text_) { textEdit->setHtml(s); } else { textEdit->setPlainText(s); } - layout->addWidget(textEdit); - - // Create dialog buttons at the bottom - QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); - layout->addWidget(buttons); - connect(buttons, SIGNAL(accepted()), this, SLOT(save())); - connect(buttons, SIGNAL(rejected()), this, SLOT(cancel())); + UpdateUIFromTextCursor(); } const QString& TextEditDialog::get_string() { @@ -94,9 +182,52 @@ void TextEditDialog::cancel() { reject(); } +void TextEditDialog::SetBold(bool bold) +{ + QFont f = textEdit->currentFont(); + f.setBold(bold); + textEdit->setCurrentFont(f); + UpdateUIFromTextCursor(); +} + +void TextEditDialog::SetFontWeight(int i) +{ + textEdit->setFontWeight(font_weight->itemData(i).toInt()); +} + +void TextEditDialog::SetLetterSpacing(qreal spacing) +{ + QFont f = textEdit->currentFont(); + f.setLetterSpacing(f.letterSpacingType(), spacing); + textEdit->setCurrentFont(f); +} + +void TextEditDialog::SetAlignmentFromProperty() +{ + textEdit->setAlignment(static_cast(sender()->property("a").toInt())); + UpdateUIFromTextCursor(); +} + void TextEditDialog::UpdateUIFromTextCursor() { italic_button->setChecked(textEdit->fontItalic()); underline_button->setChecked(textEdit->fontUnderline()); font_list->setCurrentText(textEdit->fontFamily()); + font_size->SetValue(textEdit->fontPointSize()); + font_color->set_color(textEdit->textColor()); + + for (int i=0;icount();i++) { + if (font_weight->itemData(i).toInt() == textEdit->fontWeight()) { + font_weight->blockSignals(true); + font_weight->setCurrentIndex(i); + font_weight->blockSignals(false); + break; + } + } + + Qt::Alignment align = textEdit->alignment(); + left_align_button->setChecked(align == Qt::AlignLeft); + center_align_button->setChecked(align == Qt::AlignCenter); + right_align_button->setChecked(align == Qt::AlignRight); + justify_align_button->setChecked(align == Qt::AlignJustify); } diff --git a/dialogs/texteditdialog.h b/dialogs/texteditdialog.h index 12f342b61..c2ced7d2e 100644 --- a/dialogs/texteditdialog.h +++ b/dialogs/texteditdialog.h @@ -25,6 +25,9 @@ #include #include +#include "ui/labelslider.h" +#include "ui/colorbutton.h" + class TextEditDialog : public QDialog { Q_OBJECT public: @@ -35,6 +38,11 @@ signals: private slots: void save(); void cancel(); + + void SetBold(bool bold); + void SetFontWeight(int i); + void SetLetterSpacing(qreal spacing); + void SetAlignmentFromProperty(); void UpdateUIFromTextCursor(); private: bool rich_text_; @@ -44,6 +52,13 @@ private: QPushButton* italic_button; QPushButton* underline_button; QFontComboBox* font_list; + QComboBox* font_weight; + LabelSlider* font_size; + ColorButton* font_color; + QPushButton* left_align_button; + QPushButton* center_align_button; + QPushButton* right_align_button; + QPushButton* justify_align_button; }; #endif // TEXTEDITDIALOG_H diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp index 30a1f0fef..2ce6250a7 100644 --- a/effects/internal/richtexteffect.cpp +++ b/effects/internal/richtexteffect.cpp @@ -5,8 +5,32 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : Effect(c, em) { + SetFlags(Effect::SuperimposeFlag); + EffectRow* text_row = new EffectRow(this, tr("Text")); text_val = new StringField(text_row, "text"); + + EffectRow* padding_row = new EffectRow(this, tr("Padding")); + padding_field = new DoubleField(padding_row, "padding"); + padding_field->SetColumnSpan(2); + + EffectRow* position_row = new EffectRow(this, tr("Position")); + position_x = new DoubleField(position_row, "posx"); + position_y = new DoubleField(position_row, "posy"); + + EffectRow* vertical_align_row = new EffectRow(this, tr("Vertical Align:")); + vertical_align = new ComboField(vertical_align_row, "valign"); + vertical_align->AddItem(tr("Top"), Qt::AlignTop); + vertical_align->AddItem(tr("Center"), Qt::AlignCenter); + vertical_align->AddItem(tr("Bottom"), Qt::AlignBottom); + vertical_align->SetValueAt(0, Qt::AlignCenter); + + // Create default text + text_val->SetValueAt(0, "" + "" + "
Sample Text
" + "" + ""); } void RichTextEffect::redraw(double timecode) @@ -18,7 +42,28 @@ void RichTextEffect::redraw(double timecode) img.fill(Qt::transparent); + int padding = qRound(padding_field->GetDoubleAt(timecode)); + + width -= 2 * padding; + height -= 2 * padding; + QTextDocument td; td.setHtml(text_val->GetStringAt(timecode)); - td.drawContents(&p); + td.setTextWidth(width); + + int translate_x = qRound(position_x->GetDoubleAt(timecode) + padding); + int translate_y = qRound(position_y->GetDoubleAt(timecode) + padding); + + if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) { + translate_y += height / 2 - td.size().height() / 2; + } else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) { + translate_y += height - td.size().height(); + } + + QRect clip_rect = img.rect(); + clip_rect.translate(-translate_x, -translate_y); + p.translate(translate_x, translate_y); + + + td.drawContents(&p, clip_rect); } diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h index 37eb50530..b172af288 100644 --- a/effects/internal/richtexteffect.h +++ b/effects/internal/richtexteffect.h @@ -10,6 +10,10 @@ public: void redraw(double timecode); private: StringField* text_val; + DoubleField* padding_field; + DoubleField* position_x; + DoubleField* position_y; + ComboField* vertical_align; }; #endif // RICHTEXTEFFECT_H diff --git a/icons/align-center.svg b/icons/align-center.svg new file mode 100644 index 000000000..a75dfa755 --- /dev/null +++ b/icons/align-center.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/icons/align-left.svg b/icons/align-left.svg new file mode 100644 index 000000000..379dca5b5 --- /dev/null +++ b/icons/align-left.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/icons/align-right.svg b/icons/align-right.svg new file mode 100644 index 000000000..9d1759517 --- /dev/null +++ b/icons/align-right.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/icons/bold.svg b/icons/bold.svg new file mode 100644 index 000000000..a8643a00c --- /dev/null +++ b/icons/bold.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/icons/icons.qrc b/icons/icons.qrc index d6e6f33b8..8d00cf945 100644 --- a/icons/icons.qrc +++ b/icons/icons.qrc @@ -47,5 +47,10 @@ zoomout.svg italic.svg underline.svg + align-center.svg + align-left.svg + align-right.svg + justify-center.svg + bold.svg diff --git a/icons/italic.svg b/icons/italic.svg index facb40395..c0e5700dd 100644 --- a/icons/italic.svg +++ b/icons/italic.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/icons/justify-center.svg b/icons/justify-center.svg new file mode 100644 index 000000000..73a98ff9f --- /dev/null +++ b/icons/justify-center.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/icons/underline.svg b/icons/underline.svg index a6f80735b..f82f25cd4 100644 --- a/icons/underline.svg +++ b/icons/underline.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/ui/keyframenavigator.cpp b/ui/keyframenavigator.cpp index c27e07415..9a60dd4cc 100644 --- a/ui/keyframenavigator.cpp +++ b/ui/keyframenavigator.cpp @@ -29,6 +29,8 @@ #include "ui/icons.h" KeyframeNavigator::KeyframeNavigator(QWidget *parent, bool addLeftPad) : QWidget(parent) { + setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); + key_controls = new QHBoxLayout(this); key_controls->setSpacing(0); key_controls->setMargin(0); diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp index 49ee64a8c..1688042b1 100644 --- a/ui/texteditex.cpp +++ b/ui/texteditex.cpp @@ -103,5 +103,5 @@ void TextEditEx::open_text_edit() { void TextEditEx::queue_text_modified() { - emit textModified(toPlainText()); + emit textModified(enable_rich_text_ ? toHtml() : toPlainText()); } From 16da36f36477f491a7ff5852ced28808584d1b52 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 23:34:10 +1100 Subject: [PATCH 41/56] added auto-scroll to rich text effect --- dialogs/texteditdialog.cpp | 5 +- effects/effect.cpp | 8 +--- effects/effect.h | 7 +-- effects/internal/richtexteffect.cpp | 71 +++++++++++++++++++++++++++-- effects/internal/richtexteffect.h | 3 ++ effects/internal/timecodeeffect.cpp | 6 ++- effects/internal/timecodeeffect.h | 27 ++++++----- ui/effectui.cpp | 2 +- 8 files changed, 98 insertions(+), 31 deletions(-) diff --git a/dialogs/texteditdialog.cpp b/dialogs/texteditdialog.cpp index 00e338c3a..c1fb194b3 100644 --- a/dialogs/texteditdialog.cpp +++ b/dialogs/texteditdialog.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "ui/icons.h" @@ -166,7 +167,9 @@ TextEditDialog::TextEditDialog(QWidget *parent, const QString &s, bool rich_text textEdit->setPlainText(s); } - UpdateUIFromTextCursor(); + // Helps ensure the UI elements update correctly at the beginning - when the cursor is at the start, the UI elements + // show up blank... + textEdit->moveCursor(QTextCursor::End); } const QString& TextEditDialog::get_string() { diff --git a/effects/effect.cpp b/effects/effect.cpp index 964487a90..b016c07bc 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -121,7 +121,6 @@ Effect::Effect(Clip* c, const EffectMeta *em) : flags_(0), glslProgram(nullptr), texture(nullptr), - enable_always_update_(false), isOpen(false), bound(false), iterations(1) @@ -489,12 +488,7 @@ void Effect::load_from_file() { bool Effect::AlwaysUpdate() { - return enable_always_update_; -} - -void Effect::SetAlwaysUpdate(bool b) -{ - enable_always_update_ = b; + return false; } bool Effect::IsEnabled() { diff --git a/effects/effect.h b/effects/effect.h index 4944ad5d4..acf5e255b 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -233,8 +233,8 @@ protected: QImage img; QOpenGLTexture* texture; - bool AlwaysUpdate(); - void SetAlwaysUpdate(bool b); + // enable effect to update constantly + virtual bool AlwaysUpdate(); private: bool isOpen; @@ -249,9 +249,6 @@ private: QVector gizmo_dragging_actions_; - // enable effect to update constantly - bool enable_always_update_; - // superimpose functions virtual void redraw(double timecode); bool valueHasChanged(double timecode); diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp index 2ce6250a7..d03cd2085 100644 --- a/effects/internal/richtexteffect.cpp +++ b/effects/internal/richtexteffect.cpp @@ -2,6 +2,16 @@ #include +#include "timeline/clip.h" + +enum AutoscrollDirection { + SCROLL_OFF, + SCROLL_UP, + SCROLL_DOWN, + SCROLL_LEFT, + SCROLL_RIGHT, +}; + RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : Effect(c, em) { @@ -9,6 +19,7 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : EffectRow* text_row = new EffectRow(this, tr("Text")); text_val = new StringField(text_row, "text"); + text_val->SetColumnSpan(2); EffectRow* padding_row = new EffectRow(this, tr("Padding")); padding_field = new DoubleField(padding_row, "padding"); @@ -24,6 +35,16 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : vertical_align->AddItem(tr("Center"), Qt::AlignCenter); vertical_align->AddItem(tr("Bottom"), Qt::AlignBottom); vertical_align->SetValueAt(0, Qt::AlignCenter); + vertical_align->SetColumnSpan(2); + + EffectRow* autoscroll_row = new EffectRow(this, tr("Auto-Scroll")); + autoscroll = new ComboField(autoscroll_row, "autoscroll"); + autoscroll->AddItem(tr("Off"), SCROLL_OFF); + autoscroll->AddItem(tr("Up"), SCROLL_UP); + autoscroll->AddItem(tr("Down"), SCROLL_DOWN); + autoscroll->AddItem(tr("Left"), SCROLL_LEFT); + autoscroll->AddItem(tr("Right"), SCROLL_RIGHT); + autoscroll->SetColumnSpan(2); // Create default text text_val->SetValueAt(0, "" @@ -54,10 +75,47 @@ void RichTextEffect::redraw(double timecode) int translate_x = qRound(position_x->GetDoubleAt(timecode) + padding); int translate_y = qRound(position_y->GetDoubleAt(timecode) + padding); - if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) { - translate_y += height / 2 - td.size().height() / 2; - } else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) { - translate_y += height - td.size().height(); + int doc_height = qRound(td.size().height()); + + AutoscrollDirection auto_scroll_dir = static_cast(autoscroll->GetValueAt(timecode).toInt()); + + double scroll_progress; + + if (auto_scroll_dir != SCROLL_OFF) { + double clip_length_secs = double(parent_clip->length()) / parent_clip->media_frame_rate(); + scroll_progress = (timecode - double(parent_clip->clip_in()) / parent_clip->media_frame_rate()) / clip_length_secs; + } + + if (auto_scroll_dir == SCROLL_OFF || auto_scroll_dir == SCROLL_LEFT || auto_scroll_dir == SCROLL_RIGHT) { + + // If we're not auto-scrolling the vertical direction, respect the vertical alignment + if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignCenter) { + translate_y += height / 2 - doc_height / 2; + } else if (vertical_align->GetValueAt(timecode).toInt() == Qt::AlignBottom) { + translate_y += height - doc_height; + } + + // Check if we are autoscrolling + if (auto_scroll_dir != SCROLL_OFF) { + + if (auto_scroll_dir == SCROLL_LEFT) { + scroll_progress = 1.0 - scroll_progress; + } + + int doc_width = td.size().width(); + translate_x += qRound(-doc_width + (img.width() + doc_width) * scroll_progress); + } + + } else if (auto_scroll_dir == SCROLL_UP || auto_scroll_dir == SCROLL_DOWN) { + + // Auto-scroll bottom to top or top to bottom + + if (auto_scroll_dir == SCROLL_UP) { + scroll_progress = 1.0 - scroll_progress; + } + + translate_y += qRound(-doc_height + (height + doc_height)*scroll_progress); + } QRect clip_rect = img.rect(); @@ -67,3 +125,8 @@ void RichTextEffect::redraw(double timecode) td.drawContents(&p, clip_rect); } + +bool RichTextEffect::AlwaysUpdate() +{ + return autoscroll->GetValueAt(autoscroll->Now()).toInt() != SCROLL_OFF; +} diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h index b172af288..a636be3d3 100644 --- a/effects/internal/richtexteffect.h +++ b/effects/internal/richtexteffect.h @@ -8,12 +8,15 @@ class RichTextEffect : public Effect { public: RichTextEffect(Clip* c, const EffectMeta *em); void redraw(double timecode); +protected: + virtual bool AlwaysUpdate() override; private: StringField* text_val; DoubleField* padding_field; DoubleField* position_x; DoubleField* position_y; ComboField* vertical_align; + ComboField* autoscroll; }; #endif // RICHTEXTEFFECT_H diff --git a/effects/internal/timecodeeffect.cpp b/effects/internal/timecodeeffect.cpp index 6b37a6795..43b195bc0 100644 --- a/effects/internal/timecodeeffect.cpp +++ b/effects/internal/timecodeeffect.cpp @@ -46,7 +46,6 @@ TimecodeEffect::TimecodeEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { - SetAlwaysUpdate(true); SetFlags(Effect::SuperimposeFlag); EffectRow* tc_row = new EffectRow(this, tr("Timecode")); @@ -138,3 +137,8 @@ void TimecodeEffect::redraw(double timecode) { p.setBrush(color_val->GetColorAt(timecode)); p.drawPath(path); } + +bool TimecodeEffect::AlwaysUpdate() +{ + return true; +} diff --git a/effects/internal/timecodeeffect.h b/effects/internal/timecodeeffect.h index 2f48d9bc7..d51565940 100644 --- a/effects/internal/timecodeeffect.h +++ b/effects/internal/timecodeeffect.h @@ -29,20 +29,23 @@ class TimecodeEffect : public Effect { Q_OBJECT public: - TimecodeEffect(Clip* c, const EffectMeta *em); - void redraw(double timecode); - DoubleField* scale_val; - ColorField* color_val; - ColorField* color_bg_val; - DoubleField* bg_alpha; - DoubleField* offset_x_val; - DoubleField* offset_y_val; - StringField* prepend_text; - ComboField* tc_select; + TimecodeEffect(Clip* c, const EffectMeta *em); + void redraw(double timecode); + DoubleField* scale_val; + ColorField* color_val; + ColorField* color_bg_val; + DoubleField* bg_alpha; + DoubleField* offset_x_val; + DoubleField* offset_y_val; + StringField* prepend_text; + ComboField* tc_select; + +protected: + virtual bool AlwaysUpdate() override; private: - QFont font; - QString display_timecode; + QFont font; + QString display_timecode; }; #endif // TIMECODEEFFECT_H diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 62652e7ab..6ecec732c 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -79,8 +79,8 @@ EffectUI::EffectUI(Effect* e) : } enabled_check->setChecked(e->IsEnabled()); - connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(FieldChanged())); connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(SetEnabled(bool))); + connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(FieldChanged())); } Effect *EffectUI::GetEffect() From ab0052e08e1d25e71f16ebb7b75d31256ae08eb6 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 23:57:16 +1100 Subject: [PATCH 42/56] added shadow to rich text effect and removed old effect residue --- effects/effect.cpp | 3 ++ effects/internal/richtexteffect.cpp | 73 +++++++++++++++++++++++++++-- effects/internal/richtexteffect.h | 7 +++ effects/internal/texteffect.cpp | 67 +------------------------- olive.pro | 6 ++- ui/blur.cpp | 65 +++++++++++++++++++++++++ ui/blur.h | 13 +++++ ui/colorbutton.cpp | 5 -- ui/colorbutton.h | 2 - ui/embeddedfilechooser.cpp | 5 -- ui/embeddedfilechooser.h | 2 - ui/fontcombobox.cpp | 5 -- ui/fontcombobox.h | 4 +- ui/labelslider.cpp | 2 - ui/labelslider.h | 1 - ui/texteditex.cpp | 42 ----------------- 16 files changed, 163 insertions(+), 139 deletions(-) create mode 100644 ui/blur.cpp create mode 100644 ui/blur.h diff --git a/effects/effect.cpp b/effects/effect.cpp index b016c07bc..d5ae333d6 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -373,6 +373,9 @@ void Effect::copy_field_keyframes(EffectPtr e) { // Copy keyframes between effects copy_field->keyframes = field->keyframes; + + // Copy persistet data between effects + copy_field->persistent_data_ = field->persistent_data_; } } } diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp index d03cd2085..84cb01f1f 100644 --- a/effects/internal/richtexteffect.cpp +++ b/effects/internal/richtexteffect.cpp @@ -1,8 +1,10 @@ #include "richtexteffect.h" #include +#include #include "timeline/clip.h" +#include "ui/blur.h" enum AutoscrollDirection { SCROLL_OFF, @@ -46,6 +48,34 @@ RichTextEffect::RichTextEffect(Clip *c, const EffectMeta *em) : autoscroll->AddItem(tr("Right"), SCROLL_RIGHT); autoscroll->SetColumnSpan(2); + EffectRow* shadow_row = new EffectRow(this, tr("Shadow")); + shadow_bool = new BoolField(shadow_row, "shadow"); + shadow_bool->SetColumnSpan(2); + + EffectRow* shadow_color_row = new EffectRow(this, tr("Shadow Color")); + shadow_color = new ColorField(shadow_color_row, "shadowcolor"); + shadow_color->SetColumnSpan(2); + + EffectRow* shadow_angle_row = new EffectRow(this, tr("Shadow Angle")); + shadow_angle = new DoubleField(shadow_angle_row, "shadowangle"); + shadow_angle->SetColumnSpan(2); + + EffectRow* shadow_distance_row = new EffectRow(this, tr("Shadow Distance")); + shadow_distance = new DoubleField(shadow_distance_row, "shadowdistance"); + shadow_distance->SetColumnSpan(2); + shadow_distance->SetMinimum(0); + + EffectRow* shadow_softness_row = new EffectRow(this, tr("Shadow Softness")); + shadow_softness = new DoubleField(shadow_softness_row, "shadowsoftness"); + shadow_softness->SetColumnSpan(2); + shadow_softness->SetMinimum(0); + + EffectRow* shadow_opacity_row = new EffectRow(this, tr("Shadow Opacity")); + shadow_opacity = new DoubleField(shadow_opacity_row, "shadowopacity"); + shadow_opacity->SetColumnSpan(2); + shadow_opacity->SetMinimum(0); + shadow_opacity->SetMaximum(100); + // Create default text text_val->SetValueAt(0, "" "" @@ -61,8 +91,6 @@ void RichTextEffect::redraw(double timecode) int width = img.width(); int height = img.height(); - img.fill(Qt::transparent); - int padding = qRound(padding_field->GetDoubleAt(timecode)); width -= 2 * padding; @@ -79,7 +107,7 @@ void RichTextEffect::redraw(double timecode) AutoscrollDirection auto_scroll_dir = static_cast(autoscroll->GetValueAt(timecode).toInt()); - double scroll_progress; + double scroll_progress = 0; if (auto_scroll_dir != SCROLL_OFF) { double clip_length_secs = double(parent_clip->length()) / parent_clip->media_frame_rate(); @@ -102,7 +130,7 @@ void RichTextEffect::redraw(double timecode) scroll_progress = 1.0 - scroll_progress; } - int doc_width = td.size().width(); + int doc_width = qRound(td.size().width()); translate_x += qRound(-doc_width + (img.width() + doc_width) * scroll_progress); } @@ -114,7 +142,7 @@ void RichTextEffect::redraw(double timecode) scroll_progress = 1.0 - scroll_progress; } - translate_y += qRound(-doc_height + (height + doc_height)*scroll_progress); + translate_y += qRound(-doc_height + (img.height() + doc_height)*scroll_progress); } @@ -122,8 +150,43 @@ void RichTextEffect::redraw(double timecode) clip_rect.translate(-translate_x, -translate_y); p.translate(translate_x, translate_y); + img.fill(Qt::transparent); + + // draw software shadow + if (shadow_bool->GetBoolAt(timecode)) { + + // calculate offset using distance and angle + double angle = shadow_angle->GetDoubleAt(timecode) * M_PI / 180.0; + double distance = qFloor(shadow_distance->GetDoubleAt(timecode)); + int shadow_x_offset = qRound(qCos(angle) * distance); + int shadow_y_offset = qRound(qSin(angle) * distance); + + p.translate(shadow_x_offset, shadow_y_offset); + clip_rect.translate(-shadow_x_offset, -shadow_y_offset); + + td.drawContents(&p, clip_rect); + + int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode)); + if (blurSoftness > 0) { + olive::ui::blur(img, img.rect(), blurSoftness, true); + } + + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + + p.fillRect(img.rect(), shadow_color->GetColorAt(timecode)); + + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + + p.translate(-shadow_x_offset, -shadow_y_offset); + clip_rect.translate(shadow_x_offset, shadow_y_offset); + + + + } td.drawContents(&p, clip_rect); + + p.end(); } bool RichTextEffect::AlwaysUpdate() diff --git a/effects/internal/richtexteffect.h b/effects/internal/richtexteffect.h index a636be3d3..2a8a7978b 100644 --- a/effects/internal/richtexteffect.h +++ b/effects/internal/richtexteffect.h @@ -17,6 +17,13 @@ private: DoubleField* position_y; ComboField* vertical_align; ComboField* autoscroll; + + BoolField* shadow_bool; + DoubleField* shadow_angle; + DoubleField* shadow_distance; + ColorField* shadow_color; + DoubleField* shadow_softness; + DoubleField* shadow_opacity; }; #endif // RICHTEXTEFFECT_H diff --git a/effects/internal/texteffect.cpp b/effects/internal/texteffect.cpp index 8365a57ce..ee183f0b3 100644 --- a/effects/internal/texteffect.cpp +++ b/effects/internal/texteffect.cpp @@ -40,6 +40,7 @@ #include "ui/comboboxex.h" #include "ui/colorbutton.h" #include "ui/fontcombobox.h" +#include "ui/blur.h" #include "global/config.h" TextEffect::TextEffect(Clip* c, const EffectMeta* em) : @@ -154,70 +155,6 @@ TextEffect::TextEffect(Clip* c, const EffectMeta* em) : fragPath = "dropshadow.frag"; } -void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; - - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); - - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; - - int i1 = 0; - int i2 = 3; - - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } - - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; - - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; - } -} - void TextEffect::redraw(double timecode) { QColor bkg = set_color_button->GetColorAt(timecode); bkg.setAlpha(0); @@ -340,7 +277,7 @@ void TextEffect::redraw(double timecode) { p.drawPath(shadow_path); int blurSoftness = qFloor(shadow_softness->GetDoubleAt(timecode)); - if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, true); + if (blurSoftness > 0) olive::ui::blur(img, img.rect(), blurSoftness, true); } // draw outline diff --git a/olive.pro b/olive.pro index ccf476442..ba5fd9ca1 100644 --- a/olive.pro +++ b/olive.pro @@ -173,7 +173,8 @@ SOURCES += \ effects/transition.cpp \ ui/styling.cpp \ undo/undostack.cpp \ - effects/internal/richtexteffect.cpp + effects/internal/richtexteffect.cpp \ + ui/blur.cpp HEADERS += \ ui/mainwindow.h \ @@ -300,7 +301,8 @@ HEADERS += \ effects/transition.h \ ui/styling.h \ undo/undostack.h \ - effects/internal/richtexteffect.h + effects/internal/richtexteffect.h \ + ui/blur.h FORMS += diff --git a/ui/blur.cpp b/ui/blur.cpp new file mode 100644 index 000000000..ecdf7442a --- /dev/null +++ b/ui/blur.cpp @@ -0,0 +1,65 @@ +#include "blur.h" + +void olive::ui::blur(QImage& result, const QRect& rect, int radius, bool alphaOnly) { + int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; + int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + + int r1 = rect.top(); + int r2 = rect.bottom(); + int c1 = rect.left(); + int c2 = rect.right(); + + int bpl = result.bytesPerLine(); + int rgba[4]; + unsigned char* p; + + int i1 = 0; + int i2 = 3; + + if (alphaOnly) + i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); + + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r1) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; + + p += bpl; + for (int j = r1; j < r2; j++, p += bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c1 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; + + p += 4; + for (int j = c1; j < c2; j++, p += 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + for (int col = c1; col <= c2; col++) { + p = result.scanLine(r2) + col * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; + + p -= bpl; + for (int j = r1; j < r2; j++, p -= bpl) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } + + for (int row = r1; row <= r2; row++) { + p = result.scanLine(row) + c2 * 4; + for (int i = i1; i <= i2; i++) + rgba[i] = p[i] << 4; + + p -= 4; + for (int j = c1; j < c2; j++, p -= 4) + for (int i = i1; i <= i2; i++) + p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + } +} diff --git a/ui/blur.h b/ui/blur.h new file mode 100644 index 000000000..ddf44fb86 --- /dev/null +++ b/ui/blur.h @@ -0,0 +1,13 @@ +#ifndef BLUR_H +#define BLUR_H + +#include +#include + +namespace olive { + namespace ui { + void blur(QImage& result, const QRect& rect, int radius, bool alphaOnly); + } +} + +#endif // BLUR_H diff --git a/ui/colorbutton.cpp b/ui/colorbutton.cpp index e841707b1..9423b616c 100644 --- a/ui/colorbutton.cpp +++ b/ui/colorbutton.cpp @@ -33,15 +33,10 @@ QColor ColorButton::get_color() { } void ColorButton::set_color(QColor c) { - previousColor = color; color = c; set_button_color(); } -const QColor &ColorButton::getPreviousValue() { - return previousColor; -} - void ColorButton::set_button_color() { QPalette pal = palette(); pal.setColor(QPalette::Button, color); diff --git a/ui/colorbutton.h b/ui/colorbutton.h index 944378b8c..e67ca8cd5 100644 --- a/ui/colorbutton.h +++ b/ui/colorbutton.h @@ -31,10 +31,8 @@ public: ColorButton(QWidget* parent = nullptr); QColor get_color(); void set_color(QColor c); - const QColor& getPreviousValue(); private: QColor color; - QColor previousColor; void set_button_color(); signals: void color_changed(const QColor& c); diff --git a/ui/embeddedfilechooser.cpp b/ui/embeddedfilechooser.cpp index 99e35905d..4a5bfbec2 100644 --- a/ui/embeddedfilechooser.cpp +++ b/ui/embeddedfilechooser.cpp @@ -42,12 +42,7 @@ const QString &EmbeddedFileChooser::getFilename() { return filename; } -const QString &EmbeddedFileChooser::getPreviousValue() { - return old_filename; -} - void EmbeddedFileChooser::setFilename(const QString &s) { - old_filename = filename; filename = s; update_label(); emit changed(filename); diff --git a/ui/embeddedfilechooser.h b/ui/embeddedfilechooser.h index 9d15d1264..8022022ee 100644 --- a/ui/embeddedfilechooser.h +++ b/ui/embeddedfilechooser.h @@ -31,14 +31,12 @@ public: EmbeddedFileChooser(QWidget* parent = 0); const QString& getFilename(); - const QString& getPreviousValue(); void setFilename(const QString& s); signals: void changed(const QString& s); private: QLabel* file_label; QString filename; - QString old_filename; void update_label(); private slots: void browse(); diff --git a/ui/fontcombobox.cpp b/ui/fontcombobox.cpp index 4e5547c26..c8e10d920 100644 --- a/ui/fontcombobox.cpp +++ b/ui/fontcombobox.cpp @@ -30,11 +30,6 @@ FontCombobox::FontCombobox(QWidget* parent) : QComboBox(parent) { connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(updateInternals())); } -const QString& FontCombobox::getPreviousValue() { - return previousValue; -} - void FontCombobox::updateInternals() { - previousValue = value; value = currentText(); } diff --git a/ui/fontcombobox.h b/ui/fontcombobox.h index 90fb24813..54a7b0823 100644 --- a/ui/fontcombobox.h +++ b/ui/fontcombobox.h @@ -26,12 +26,10 @@ class FontCombobox : public QComboBox { Q_OBJECT public: - FontCombobox(QWidget* parent = 0); - const QString &getPreviousValue(); + FontCombobox(QWidget* parent = nullptr); private slots: void updateInternals(); private: - QString previousValue; QString value; }; diff --git a/ui/labelslider.cpp b/ui/labelslider.cpp index 94751124e..f83165abf 100644 --- a/ui/labelslider.cpp +++ b/ui/labelslider.cpp @@ -245,8 +245,6 @@ void LabelSlider::mouseReleaseEvent(QMouseEvent*) { drag_proc = false; - previous_value = drag_start_value; - emit valueChanged(internal_value); } else { diff --git a/ui/labelslider.h b/ui/labelslider.h index e7550513c..c1402d1de 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -160,7 +160,6 @@ private: double default_value; double internal_value; double drag_start_value; - double previous_value; int decimal_places; diff --git a/ui/texteditex.cpp b/ui/texteditex.cpp index 1688042b1..7c558ce98 100644 --- a/ui/texteditex.cpp +++ b/ui/texteditex.cpp @@ -21,48 +21,6 @@ #include "texteditex.h" #include - -/* -TextEditEx::TextEditEx(QWidget *parent) : QTextEdit(parent) { - setUndoRedoEnabled(false); - connect(this, SIGNAL(textChanged()), this, SLOT(updateInternals())); - connect(this, SIGNAL(updateSelf()), this, SLOT(updateText())); -} - -const QString& TextEditEx::getPlainTextEx() { - return text; -} - -void TextEditEx::setPlainTextEx(const QString &t) { - previousText = text; - text = t; - emit updateSelf(); -} - -const QString &TextEditEx::getPreviousValue() { - return previousText; -} - -void TextEditEx::updateInternals() { - previousText = text; - text = toPlainText(); -} - -void TextEditEx::updateText() { - blockSignals(true); - - int pos = textCursor().position(); - - setPlainText(text); - - QTextCursor newCursor(document()); - newCursor.setPosition(pos); - setTextCursor(newCursor); - - blockSignals(false); -} -*/ - #include #include "dialogs/texteditdialog.h" From 058e5b25c526f1dd71dd2973efd51fc97686522c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 01:26:46 +1100 Subject: [PATCH 43/56] started on editing multiple effects at once --- effects/fields/boolfield.cpp | 8 ++++- effects/fields/doublefield.cpp | 6 +++- effects/internal/richtexteffect.cpp | 3 -- panels/effectcontrols.cpp | 28 ++++++++++-------- ui/effectui.cpp | 46 +++++++++++++++++++++++++++++ ui/effectui.h | 8 ++++- 6 files changed, 80 insertions(+), 19 deletions(-) diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp index 33102544d..f47f1d5e3 100644 --- a/effects/fields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -31,7 +31,13 @@ void BoolField::UpdateWidgetValue(QWidget *widget, double timecode) cb->blockSignals(true); - cb->setChecked(GetBoolAt(timecode)); + if (qIsNaN(timecode)) { + cb->setTristate(true); + cb->setCheckState(Qt::PartiallyChecked); + } else { + cb->setTristate(false); + cb->setChecked(GetBoolAt(timecode)); + } cb->blockSignals(false); diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 378d18879..900eb84b2 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -86,7 +86,11 @@ QWidget *DoubleField::CreateWidget() void DoubleField::UpdateWidgetValue(QWidget *widget, double timecode) { - static_cast(widget)->SetValue(GetDoubleAt(timecode)); + if (qIsNaN(timecode)) { + static_cast(widget)->SetValue(qSNaN()); + } else { + static_cast(widget)->SetValue(GetDoubleAt(timecode)); + } } void DoubleField::ValueHasBeenSet() diff --git a/effects/internal/richtexteffect.cpp b/effects/internal/richtexteffect.cpp index 84cb01f1f..34ab317bb 100644 --- a/effects/internal/richtexteffect.cpp +++ b/effects/internal/richtexteffect.cpp @@ -179,9 +179,6 @@ void RichTextEffect::redraw(double timecode) p.translate(-shadow_x_offset, -shadow_y_offset); clip_rect.translate(shadow_x_offset, shadow_y_offset); - - - } td.drawContents(&p, clip_rect); diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index dcc83bfbf..7ad83e43a 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -133,18 +133,7 @@ void EffectControls::menu_select(QAction* q) { void EffectControls::update_keyframes() { for (int i=0;iGetEffect(); - - for (int j=0;jrow_count();j++) { - - EffectRow* row = effect->row(j); - - for (int k=0;kFieldCount();k++) { - EffectField* field = row->Field(k); - - field->UpdateWidgetValue(ui->Widget(j, k), field->Now()); - } - } + ui->UpdateFromEffect(); } headers->update_zoom(zoom); @@ -607,7 +596,20 @@ void EffectControls::Load() { if (mode_ == kTransitionNone) { for (int j=0;jeffects.size();j++) { - open_effect(layout, c->effects.at(j).get()); + + // Check if we've already opened an effect of this type before + bool already_opened = false; + for (int k=0;kGetEffect()->meta == c->effects.at(j)->meta) { + open_effects_.at(k)->AddAdditionalEffect(c->effects.at(j).get()); + already_opened = true; + break; + } + } + + if (!already_opened) { + open_effect(layout, c->effects.at(j).get()); + } // Check if one of the open effects contains the row currently active in the graph editor. If not, we'll have // to clear the graph editor later. diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 6ecec732c..b79b5243f 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -83,6 +83,11 @@ EffectUI::EffectUI(Effect* e) : connect(enabled_check, SIGNAL(toggled(bool)), e, SLOT(FieldChanged())); } +void EffectUI::AddAdditionalEffect(Effect *e) +{ + additional_effects_.append(e); +} + Effect *EffectUI::GetEffect() { return effect_; @@ -96,6 +101,47 @@ int EffectUI::GetRowY(int row, QWidget* mapToWidget) { - title_bar->height(); } +void EffectUI::UpdateFromEffect() +{ + Effect* effect = GetEffect(); + + for (int j=0;jrow_count();j++) { + + EffectRow* row = effect->row(j); + + for (int k=0;kFieldCount();k++) { + EffectField* field = row->Field(k); + + // Check if this UI object is attached to one effect or many + if (additional_effects_.isEmpty()) { + + field->UpdateWidgetValue(Widget(j, k), field->Now()); + + } else { + + bool same_value = true; + + for (int i=0;i 0 ? additional_effects_.at(i-1)->row(j)->Field(k) : field; + EffectField* additional_field = additional_effects_.at(i)->row(j)->Field(k); + + if (additional_field->GetValueAt(additional_field->Now()) != previous_field->GetValueAt(previous_field->Now())) { + same_value = false; + break; + } + } + + if (same_value) { + field->UpdateWidgetValue(Widget(j, k), field->Now()); + } else { + field->UpdateWidgetValue(Widget(j, k), qSNaN()); + } + + } + } + } +} + QWidget *EffectUI::Widget(int row, int field) { return widgets_.at(row).at(field); diff --git a/ui/effectui.h b/ui/effectui.h index 81de6871e..b63434b07 100644 --- a/ui/effectui.h +++ b/ui/effectui.h @@ -9,17 +9,23 @@ class EffectUI : public CollapsibleWidget { public: EffectUI(Effect* e); + void AddAdditionalEffect(Effect* e); + Effect* GetEffect(); int GetRowY(int row, QWidget *mapToWidget); - QWidget* Widget(int row, int field); + void UpdateFromEffect(); + signals: void CutRequested(); void CopyRequested(); void TitleBarContextMenuRequested(const QPoint&); private: + QWidget* Widget(int row, int field); + Effect* effect_; + QVector additional_effects_; QGridLayout* layout_; QVector labels_; QVector< QVector > widgets_; From db22704169ad1a8414a784de616a81e9505eb2ca Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 09:59:31 +1100 Subject: [PATCH 44/56] implemented #92 --- effects/effectfield.cpp | 4 +- effects/effectfield.h | 2 +- effects/effectrow.cpp | 5 ++ effects/effectrow.h | 1 + effects/fields/boolfield.cpp | 15 +++++- effects/fields/boolfield.h | 2 +- effects/fields/buttonfield.cpp | 20 ++++++-- effects/fields/buttonfield.h | 2 +- effects/fields/colorfield.cpp | 4 +- effects/fields/colorfield.h | 2 +- effects/fields/combofield.cpp | 16 +++++-- effects/fields/combofield.h | 2 +- effects/fields/doublefield.cpp | 35 ++++++++------ effects/fields/doublefield.h | 6 +-- effects/fields/filefield.cpp | 4 +- effects/fields/filefield.h | 2 +- effects/fields/fontfield.cpp | 16 +++++-- effects/fields/fontfield.h | 2 +- effects/fields/labelfield.cpp | 17 +++++-- effects/fields/labelfield.h | 2 +- effects/fields/stringfield.cpp | 26 +++++++---- effects/fields/stringfield.h | 2 +- panels/effectcontrols.cpp | 3 ++ ui/collapsiblewidget.cpp | 9 +++- ui/collapsiblewidget.h | 3 +- ui/effectui.cpp | 85 +++++++++++++++++++++++++++++----- ui/effectui.h | 5 ++ 27 files changed, 220 insertions(+), 72 deletions(-) diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index 3afec20c0..0321e8d76 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -95,9 +95,9 @@ QString EffectField::ConvertValueToString(const QVariant &v) return v.toString(); } -QWidget *EffectField::CreateWidget() +QWidget *EffectField::CreateWidget(QWidget *existing) { - return new QLabel(tr("(Invalid field)")); + return (existing == nullptr) ? new QLabel(tr("(Invalid field)")) : existing; } void EffectField::UpdateWidgetValue(QWidget *, double) {} diff --git a/effects/effectfield.h b/effects/effectfield.h index 767090920..af3e236e6 100644 --- a/effects/effectfield.h +++ b/effects/effectfield.h @@ -68,7 +68,7 @@ public: virtual QVariant ConvertStringToValue(const QString& s); virtual QString ConvertValueToString(const QVariant& v); - virtual QWidget* CreateWidget(); + virtual QWidget* CreateWidget(QWidget* existing = nullptr); virtual void UpdateWidgetValue(QWidget* widget, double); double GetValidKeyframeHandlePosition(int key, bool post); diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index 713222927..d61980fa2 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -71,6 +71,11 @@ bool EffectRow::IsSavable() return savable_; } +bool EffectRow::IsKeyframable() +{ + return keyframable_; +} + void EffectRow::SetKeyframingEnabled(bool enabled) { if (enabled) { diff --git a/effects/effectrow.h b/effects/effectrow.h index b3be99aed..71df69f15 100644 --- a/effects/effectrow.h +++ b/effects/effectrow.h @@ -56,6 +56,7 @@ public: void SetKeyframingInternal(bool); bool IsSavable(); + bool IsKeyframable(); public slots: void GoToPreviousKeyframe(); void ToggleKeyframe(); diff --git a/effects/fields/boolfield.cpp b/effects/fields/boolfield.cpp index f47f1d5e3..7fc7c2a4d 100644 --- a/effects/fields/boolfield.cpp +++ b/effects/fields/boolfield.cpp @@ -11,9 +11,20 @@ bool BoolField::GetBoolAt(double timecode) return GetValueAt(timecode).toBool(); } -QWidget *BoolField::CreateWidget() +QWidget *BoolField::CreateWidget(QWidget *existing) { - QCheckBox* cb = new QCheckBox(); + QCheckBox* cb; + + if (existing == nullptr) { + + cb = new QCheckBox(); + cb->setEnabled(IsEnabled()); + + } else { + + cb = static_cast(existing); + + } connect(cb, SIGNAL(toggled(bool)), this, SLOT(UpdateFromWidget(bool))); connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); diff --git a/effects/fields/boolfield.h b/effects/fields/boolfield.h index 0ac09a01e..5af612530 100644 --- a/effects/fields/boolfield.h +++ b/effects/fields/boolfield.h @@ -11,7 +11,7 @@ public: bool GetBoolAt(double timecode); - virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; virtual QVariant ConvertStringToValue(const QString& s) override; diff --git a/effects/fields/buttonfield.cpp b/effects/fields/buttonfield.cpp index 57845808f..23cc860af 100644 --- a/effects/fields/buttonfield.cpp +++ b/effects/fields/buttonfield.cpp @@ -18,13 +18,23 @@ void ButtonField::SetChecked(bool c) emit CheckedChanged(c); } -QWidget *ButtonField::CreateWidget() +QWidget *ButtonField::CreateWidget(QWidget *existing) { - QPushButton* button = new QPushButton(); + QPushButton* button; - button->setCheckable(checkable_); - button->setEnabled(IsEnabled()); - button->setText(button_text_); + if (existing == nullptr) { + + button = new QPushButton(); + + button->setCheckable(checkable_); + button->setEnabled(IsEnabled()); + button->setText(button_text_); + + } else { + + button = static_cast(existing); + + } connect(this, SIGNAL(CheckedChanged(bool)), button, SLOT(setChecked(bool))); connect(this, SIGNAL(EnabledChanged(bool)), button, SLOT(setEnabled(bool))); diff --git a/effects/fields/buttonfield.h b/effects/fields/buttonfield.h index c3e3150f7..940e458e5 100644 --- a/effects/fields/buttonfield.h +++ b/effects/fields/buttonfield.h @@ -10,7 +10,7 @@ public: ButtonField(EffectRow* parent, const QString& string); void SetCheckable(bool c); - virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; public slots: void SetChecked(bool c); diff --git a/effects/fields/colorfield.cpp b/effects/fields/colorfield.cpp index a48c4b841..a70135af4 100644 --- a/effects/fields/colorfield.cpp +++ b/effects/fields/colorfield.cpp @@ -13,9 +13,9 @@ QColor ColorField::GetColorAt(double timecode) return GetValueAt(timecode).value(); } -QWidget *ColorField::CreateWidget() +QWidget *ColorField::CreateWidget(QWidget *existing) { - ColorButton* cb = new ColorButton(); + ColorButton* cb = (existing != nullptr) ? static_cast(existing) : new ColorButton(); connect(cb, SIGNAL(color_changed(const QColor &)), this, SLOT(UpdateFromWidget(const QColor &))); connect(this, SIGNAL(EnabledChanged(bool)), cb, SLOT(setEnabled(bool))); diff --git a/effects/fields/colorfield.h b/effects/fields/colorfield.h index 9ff0b03c4..ab32e4b52 100644 --- a/effects/fields/colorfield.h +++ b/effects/fields/colorfield.h @@ -11,7 +11,7 @@ public: QColor GetColorAt(double timecode); - virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; virtual QVariant ConvertStringToValue(const QString& s) override; diff --git a/effects/fields/combofield.cpp b/effects/fields/combofield.cpp index 828705f67..ad43bb4f5 100644 --- a/effects/fields/combofield.cpp +++ b/effects/fields/combofield.cpp @@ -18,14 +18,20 @@ void ComboField::AddItem(const QString &text, const QVariant &data) items_.append(item); } -QWidget *ComboField::CreateWidget() +QWidget *ComboField::CreateWidget(QWidget *existing) { - ComboBoxEx* cb = new ComboBoxEx(); + ComboBoxEx* cb; - cb->setScrollingEnabled(false); + if (existing == nullptr) { + cb = new ComboBoxEx(); - for (int i=0;iaddItem(items_.at(i).name); + cb->setScrollingEnabled(false); + + for (int i=0;iaddItem(items_.at(i).name); + } + } else { + cb = static_cast(existing); } connect(cb, SIGNAL(activated(int)), this, SLOT(UpdateFromWidget(int))); diff --git a/effects/fields/combofield.h b/effects/fields/combofield.h index d9c81e60a..c2b1cb295 100644 --- a/effects/fields/combofield.h +++ b/effects/fields/combofield.h @@ -16,7 +16,7 @@ public: void AddItem(const QString& text, const QVariant& data); - virtual QWidget *CreateWidget() override; + virtual QWidget *CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; signals: diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 900eb84b2..64d338587 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -60,22 +60,31 @@ QString DoubleField::ConvertValueToString(const QVariant &v) return QString::number(v.toDouble()); } -QWidget *DoubleField::CreateWidget() +QWidget *DoubleField::CreateWidget(QWidget *existing) { - LabelSlider* ls = new LabelSlider(); + LabelSlider* ls; - if (!qIsNaN(min_)) { - ls->SetMinimum(min_); - } - ls->SetDefault(default_); - if (!qIsNaN(max_)) { - ls->SetMaximum(max_); - } - ls->SetDisplayType(display_type_); - ls->SetFrameRate(frame_rate_); + if (existing == nullptr) { - //qDebug() << ""; - ls->setEnabled(IsEnabled()); + ls = new LabelSlider(); + + if (!qIsNaN(min_)) { + ls->SetMinimum(min_); + } + ls->SetDefault(default_); + if (!qIsNaN(max_)) { + ls->SetMaximum(max_); + } + ls->SetDisplayType(display_type_); + ls->SetFrameRate(frame_rate_); + + ls->setEnabled(IsEnabled()); + + } else { + + ls = static_cast(existing); + + } connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double))); connect(ls, SIGNAL(clicked()), this, SIGNAL(Clicked())); diff --git a/effects/fields/doublefield.h b/effects/fields/doublefield.h index 935e895bf..4ba53da8a 100644 --- a/effects/fields/doublefield.h +++ b/effects/fields/doublefield.h @@ -32,10 +32,10 @@ public: void SetDisplayType(LabelSlider::DisplayType type); void SetFrameRate(const double& rate); - virtual QVariant ConvertStringToValue(const QString& s); - virtual QString ConvertValueToString(const QVariant& v); + virtual QVariant ConvertStringToValue(const QString& s) override; + virtual QString ConvertValueToString(const QVariant& v) override; - virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; private: double min_; diff --git a/effects/fields/filefield.cpp b/effects/fields/filefield.cpp index 27698c94c..bf5125ae8 100644 --- a/effects/fields/filefield.cpp +++ b/effects/fields/filefield.cpp @@ -13,9 +13,9 @@ QString FileField::GetFileAt(double timecode) return GetValueAt(timecode).toString(); } -QWidget *FileField::CreateWidget() +QWidget *FileField::CreateWidget(QWidget *existing) { - EmbeddedFileChooser* efc = new EmbeddedFileChooser(); + EmbeddedFileChooser* efc = (existing != nullptr) ? static_cast(existing) : new EmbeddedFileChooser(); connect(efc, SIGNAL(changed(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); connect(this, SIGNAL(EnabledChanged(bool)), efc, SLOT(setEnabled(bool))); diff --git a/effects/fields/filefield.h b/effects/fields/filefield.h index ef1e1e099..88c3f0237 100644 --- a/effects/fields/filefield.h +++ b/effects/fields/filefield.h @@ -11,7 +11,7 @@ public: QString GetFileAt(double timecode); - virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; private slots: void UpdateFromWidget(const QString &s); }; diff --git a/effects/fields/fontfield.cpp b/effects/fields/fontfield.cpp index c95c87697..8ee06877a 100644 --- a/effects/fields/fontfield.cpp +++ b/effects/fields/fontfield.cpp @@ -20,13 +20,23 @@ QString FontField::GetFontAt(double timecode) return GetValueAt(timecode).toString(); } -QWidget *FontField::CreateWidget() +QWidget *FontField::CreateWidget(QWidget *existing) { ComboBoxEx* fcb = new ComboBoxEx(); - fcb->setScrollingEnabled(false); + if (existing == nullptr) { - fcb->addItems(font_list); + fcb = new ComboBoxEx(); + + fcb->setScrollingEnabled(false); + + fcb->addItems(font_list); + + } else { + + fcb = static_cast(existing); + + } connect(fcb, SIGNAL(currentTextChanged(const QString &)), this, SLOT(UpdateFromWidget(const QString &))); connect(this, SIGNAL(EnabledChanged(bool)), fcb, SLOT(setEnabled(bool))); diff --git a/effects/fields/fontfield.h b/effects/fields/fontfield.h index f8b095d2b..9df3e76ae 100644 --- a/effects/fields/fontfield.h +++ b/effects/fields/fontfield.h @@ -10,7 +10,7 @@ public: QString GetFontAt(double timecode); - virtual QWidget *CreateWidget() override; + virtual QWidget *CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; private: diff --git a/effects/fields/labelfield.cpp b/effects/fields/labelfield.cpp index e50f337d8..b3eccfa6d 100644 --- a/effects/fields/labelfield.cpp +++ b/effects/fields/labelfield.cpp @@ -7,11 +7,22 @@ LabelField::LabelField(EffectRow *parent, const QString &string) : label_text_(string) {} -QWidget *LabelField::CreateWidget() +QWidget *LabelField::CreateWidget(QWidget *existing) { - QLabel* label = new QLabel(label_text_); + QLabel* label; + + if (existing == nullptr) { + + label = new QLabel(label_text_); + + label->setEnabled(IsEnabled()); + + } else { + + label = static_cast(existing); + + } - label->setEnabled(IsEnabled()); connect(this, SIGNAL(EnabledChanged(bool)), label, SLOT(setEnabled(bool))); return label; diff --git a/effects/fields/labelfield.h b/effects/fields/labelfield.h index 31a40462b..67b4728f4 100644 --- a/effects/fields/labelfield.h +++ b/effects/fields/labelfield.h @@ -9,7 +9,7 @@ class LabelField : public EffectField public: LabelField(EffectRow* parent, const QString& string); - virtual QWidget* CreateWidget() override; + virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; private: QString label_text_; }; diff --git a/effects/fields/stringfield.cpp b/effects/fields/stringfield.cpp index 45d7b023c..55b59752d 100644 --- a/effects/fields/stringfield.cpp +++ b/effects/fields/stringfield.cpp @@ -18,17 +18,27 @@ QString StringField::GetStringAt(double timecode) return GetValueAt(timecode).toString(); } -QWidget *StringField::CreateWidget() +QWidget *StringField::CreateWidget(QWidget *existing) { - TextEditEx* text_edit = new TextEditEx(nullptr, rich_text_); + TextEditEx* text_edit; - text_edit->setEnabled(IsEnabled()); - text_edit->setUndoRedoEnabled(true); + if (existing == nullptr) { - // the "2" looks like a magic number, but it's just one pixel on the top and the bottom - text_edit->setFixedHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines - + text_edit->document()->documentMargin() - + text_edit->document()->documentMargin() + 2)); + text_edit = new TextEditEx(nullptr, rich_text_); + + text_edit->setEnabled(IsEnabled()); + text_edit->setUndoRedoEnabled(true); + + // the "2" is because the height needs one extra pixel of padding on the top and the bottom + text_edit->setFixedHeight(qCeil(text_edit->fontMetrics().lineSpacing()*olive::CurrentConfig.effect_textbox_lines + + text_edit->document()->documentMargin() + + text_edit->document()->documentMargin() + 2)); + + } else { + + text_edit = static_cast(existing); + + } connect(text_edit, SIGNAL(textModified(const QString&)), this, SLOT(UpdateFromWidget(const QString&))); connect(this, SIGNAL(EnabledChanged(bool)), text_edit, SLOT(setEnabled(bool))); diff --git a/effects/fields/stringfield.h b/effects/fields/stringfield.h index 6202afb27..01eb26e9d 100644 --- a/effects/fields/stringfield.h +++ b/effects/fields/stringfield.h @@ -11,7 +11,7 @@ public: QString GetStringAt(double timecode); - virtual QWidget *CreateWidget() override; + virtual QWidget *CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; private slots: void UpdateFromWidget(const QString& b); diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 7ad83e43a..a221c8f98 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -601,8 +601,11 @@ void EffectControls::Load() { bool already_opened = false; for (int k=0;kGetEffect()->meta == c->effects.at(j)->meta) { + open_effects_.at(k)->AddAdditionalEffect(c->effects.at(j).get()); + already_opened = true; + break; } } diff --git a/ui/collapsiblewidget.cpp b/ui/collapsiblewidget.cpp index fb3e94bc6..e81c3dbc8 100644 --- a/ui/collapsiblewidget.cpp +++ b/ui/collapsiblewidget.cpp @@ -53,7 +53,7 @@ CollapsibleWidget::CollapsibleWidget(QWidget* parent) : QWidget(parent) { collapse_button = new QPushButton(title_bar); collapse_button->setIconSize(collapse_button->iconSize()*0.5); collapse_button->setFlat(true); - SetText(tr("")); + SetTitle(tr("")); title_bar_layout->addWidget(collapse_button); title_bar_layout->addWidget(enabled_check); title_bar_layout->addWidget(header); @@ -108,7 +108,12 @@ void CollapsibleWidget::SetContents(QWidget* c) { } } -void CollapsibleWidget::SetText(const QString &s) { +QString CollapsibleWidget::Title() +{ + return header->text(); +} + +void CollapsibleWidget::SetTitle(const QString &s) { header->setText(s); } diff --git a/ui/collapsiblewidget.h b/ui/collapsiblewidget.h index d13ebd300..8aa67ebb4 100644 --- a/ui/collapsiblewidget.h +++ b/ui/collapsiblewidget.h @@ -50,7 +50,8 @@ class CollapsibleWidget : public QWidget public: CollapsibleWidget(QWidget* parent = nullptr); void SetContents(QWidget* c); - void SetText(const QString &); + QString Title(); + void SetTitle(const QString &); bool IsFocused(); bool IsExpanded(); bool IsSelected(); diff --git a/ui/effectui.cpp b/ui/effectui.cpp index b79b5243f..e5e5ac734 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -6,14 +6,16 @@ #include "timeline/clip.h" #include "ui/menuhelper.h" #include "ui/keyframenavigator.h" +#include "ui/clickablelabel.h" #include "panels/panels.h" EffectUI::EffectUI(Effect* e) : - effect_(e) + effect_(e), + multiple_(false) { Q_ASSERT(e != nullptr); - SetText(e->name); + SetTitle(e->name); QWidget* ui = new QWidget(this); SetContents(ui); @@ -33,7 +35,8 @@ EffectUI::EffectUI(Effect* e) : for (int i=0;irow_count();i++) { EffectRow* row = e->row(i); - QLabel* row_label = new QLabel(row->name()); + ClickableLabel* row_label = new ClickableLabel(row->name()); + connect(row_label, SIGNAL(clicked()), row, SLOT(FocusRow())); labels_.append(row_label); @@ -61,21 +64,32 @@ EffectUI::EffectUI(Effect* e) : // Create keyframe controls maximum_column++; + keyframe_navigators_.resize(e->row_count()); + for (int i=0;irow_count();i++) { EffectRow* row = e->row(i); - KeyframeNavigator* nav = new KeyframeNavigator(); + KeyframeNavigator* nav; - nav->enable_keyframes(row->IsKeyframing()); + if (row->IsKeyframable()) { - connect(nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); - connect(nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); - connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); - connect(nav, SIGNAL(keyframe_enabled_changed(bool)), row, SLOT(SetKeyframingEnabled(bool))); - connect(nav, SIGNAL(clicked()), row, SLOT(FocusRow())); - connect(row, SIGNAL(KeyframingSetChanged(bool)), nav, SLOT(enable_keyframes(bool))); + nav = new KeyframeNavigator(); + + nav->enable_keyframes(row->IsKeyframing()); + + AttachKeyframeNavigationToRow(row, nav); + + layout_->addWidget(nav, i, maximum_column); + + } else { + + nav = nullptr; + + } + + + keyframe_navigators_[i] = nav; - layout_->addWidget(nav, i, maximum_column); } enabled_check->setChecked(e->IsEnabled()); @@ -85,7 +99,34 @@ EffectUI::EffectUI(Effect* e) : void EffectUI::AddAdditionalEffect(Effect *e) { + // Ensure this is the same kind of effect and will be fully compatible + Q_ASSERT(e->meta == effect_->meta); + + // Add multiple modifer to header label + QString new_title = QString(tr("%1 (multiple)")).arg(Title()); + SetTitle(new_title); + + // Add effect to list additional_effects_.append(e); + + // Attach this UI's widgets to the additional effect + for (int i=0;irow_count();i++) { + + EffectRow* row = effect_->row(i); + + // Attach existing keyframe navigator to this effect's row + AttachKeyframeNavigationToRow(e->row(i), keyframe_navigators_.at(i)); + + for (int j=0;jFieldCount();j++) { + + EffectField* field = row->Field(j); + + // Attach existing field widget to this effect's field + e->row(i)->Field(j)->CreateWidget(Widget(i, j)); + + } + + } } Effect *EffectUI::GetEffect() @@ -94,7 +135,13 @@ Effect *EffectUI::GetEffect() } int EffectUI::GetRowY(int row, QWidget* mapToWidget) { + + // Currently to get a Y value in the context of `mapToWidget`, we use `panel_effect_controls` as the base. Mapping + // to global doesn't work for some reason, so this is the best reference point we have. + QLabel* row_label = labels_.at(row); + + // Get center point of label (label->rect()->center()->y() - instead of y()+height/2 - produces an inaccurate result) return row_label->y() + row_label->height() / 2 + mapToWidget->mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() @@ -147,6 +194,20 @@ QWidget *EffectUI::Widget(int row, int field) return widgets_.at(row).at(field); } +void EffectUI::AttachKeyframeNavigationToRow(EffectRow *row, KeyframeNavigator *nav) +{ + if (nav == nullptr) { + return; + } + + connect(nav, SIGNAL(goto_previous_key()), row, SLOT(GoToPreviousKeyframe())); + connect(nav, SIGNAL(toggle_key()), row, SLOT(ToggleKeyframe())); + connect(nav, SIGNAL(goto_next_key()), row, SLOT(GoToNextKeyframe())); + connect(nav, SIGNAL(keyframe_enabled_changed(bool)), row, SLOT(SetKeyframingEnabled(bool))); + connect(nav, SIGNAL(clicked()), row, SLOT(FocusRow())); + connect(row, SIGNAL(KeyframingSetChanged(bool)), nav, SLOT(enable_keyframes(bool))); +} + void EffectUI::show_context_menu(const QPoint& pos) { if (effect_->meta->type == EFFECT_TYPE_EFFECT) { QMenu menu; diff --git a/ui/effectui.h b/ui/effectui.h index b63434b07..7e448a8d9 100644 --- a/ui/effectui.h +++ b/ui/effectui.h @@ -29,6 +29,11 @@ private: QGridLayout* layout_; QVector labels_; QVector< QVector > widgets_; + QVector keyframe_navigators_; + + bool multiple_; + + void AttachKeyframeNavigationToRow(EffectRow* row, KeyframeNavigator* nav); private slots: void show_context_menu(const QPoint&); }; From ba700fa13ffc446d9dff318b92c45ce6a45cf9e1 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 10:31:43 +1100 Subject: [PATCH 45/56] fixed auto-scale breaking positioning --- rendering/renderfunctions.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index da22f9ff3..2d889ed6e 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -400,14 +400,6 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { coords.blendmode = -1; coords.opacity = 1.0; - // if auto-scale is enabled, auto-scale the clip - if (c->autoscaled() && (video_width != s->width && video_height != s->height)) { - float width_multiplier = float(s->width) / float(video_width); - float height_multiplier = float(s->height) / float(video_height); - float scale_multiplier = qMin(width_multiplier, height_multiplier); - glScalef(scale_multiplier, scale_multiplier, 1); - } - // == EFFECT CODE START == // get current sequence time in seconds (used for effects) @@ -418,10 +410,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { Effect* e = c->effects.at(j).get(); process_effect(c, e, timecode, coords, textureID, fbo_switcher, params.texture_failed, kTransitionNone); - if (e == params.gizmos) { - e->gizmo_draw(timecode, coords); // set correct gizmo coords - e->gizmo_world_to_screen(); // convert gizmo coords to screen coords - } + } // if the clip has an opening transition, process that now @@ -442,6 +431,25 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // == EFFECT CODE END == + + // Check whether the parent clip is auto-scaledc + if (c->autoscaled() + && (video_width != s->width + && video_height != s->height)) { + float width_multiplier = float(s->width) / float(video_width); + float height_multiplier = float(s->height) / float(video_height); + float scale_multiplier = qMin(width_multiplier, height_multiplier); + glScalef(scale_multiplier, scale_multiplier, 1); + } + + // Configure effect gizmos if they exist + if (params.gizmos != nullptr) { + params.gizmos->gizmo_draw(timecode, coords); // set correct gizmo coords + params.gizmos->gizmo_world_to_screen(); // convert gizmo coords to screen coords + } + + + if (textureID > 0) { // set viewport to sequence size params.ctx->functions()->glViewport(0, 0, s->width, s->height); From d32ff84240c393b8581abbcaf7e9812fa6be53b4 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 10:43:57 +1100 Subject: [PATCH 46/56] fixed multiple clip issues --- panels/effectcontrols.cpp | 3 ++- ui/effectui.cpp | 26 +++++++++++++++++++++++--- ui/effectui.h | 2 ++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index a221c8f98..f306ec031 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -600,7 +600,8 @@ void EffectControls::Load() { // Check if we've already opened an effect of this type before bool already_opened = false; for (int k=0;kGetEffect()->meta == c->effects.at(j)->meta) { + if (open_effects_.at(k)->GetEffect()->meta == c->effects.at(j)->meta + && !open_effects_.at(k)->IsAttachedToClip(c)) { open_effects_.at(k)->AddAdditionalEffect(c->effects.at(j).get()); diff --git a/ui/effectui.cpp b/ui/effectui.cpp index e5e5ac734..8ec85ba97 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -102,9 +102,14 @@ void EffectUI::AddAdditionalEffect(Effect *e) // Ensure this is the same kind of effect and will be fully compatible Q_ASSERT(e->meta == effect_->meta); - // Add multiple modifer to header label - QString new_title = QString(tr("%1 (multiple)")).arg(Title()); - SetTitle(new_title); + // Add multiple modifer to header label (but only once) + if (!multiple_) { + QString new_title = QString(tr("%1 (multiple)")).arg(Title()); + + SetTitle(new_title); + + multiple_ = true; + } // Add effect to list additional_effects_.append(e); @@ -189,6 +194,21 @@ void EffectUI::UpdateFromEffect() } } +bool EffectUI::IsAttachedToClip(Clip *c) +{ + if (GetEffect()->parent_clip == c) { + return true; + } + + for (int i=0;iparent_clip == c) { + return true; + } + } + + return false; +} + QWidget *EffectUI::Widget(int row, int field) { return widgets_.at(row).at(field); diff --git a/ui/effectui.h b/ui/effectui.h index 7e448a8d9..eb9be8dbf 100644 --- a/ui/effectui.h +++ b/ui/effectui.h @@ -17,6 +17,8 @@ public: void UpdateFromEffect(); + bool IsAttachedToClip(Clip* c); + signals: void CutRequested(); void CopyRequested(); From bc01f57b176019805611edc5485cac0f57f86abb Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 11:23:31 +1100 Subject: [PATCH 47/56] transitions can be correctly edited in effect controls --- effects/transition.cpp | 5 -- effects/transition.h | 3 +- panels/effectcontrols.cpp | 119 +++++++++++++++++++++++++------------- panels/panels.cpp | 2 - ui/effectui.cpp | 23 +++++++- 5 files changed, 100 insertions(+), 52 deletions(-) diff --git a/effects/transition.cpp b/effects/transition.cpp index 1378823c3..18b064ed7 100644 --- a/effects/transition.cpp +++ b/effects/transition.cpp @@ -52,7 +52,6 @@ Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : length_field->SetDisplayType(LabelSlider::FrameNumber); length_field->SetFrameRate(parent_clip->sequence == nullptr ? parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); - connect(length_field, SIGNAL(changed()), this, SLOT(set_length_from_slider())); } TransitionPtr Transition::copy(Clip *c, Clip *s) { @@ -97,10 +96,6 @@ Clip* Transition::get_closed_clip() { return nullptr; } -void Transition::set_length_from_slider() { - update_ui(false); -} - TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s, const EffectMeta* em) { if (!em->filename.isEmpty()) { // load effect from file diff --git a/effects/transition.h b/effects/transition.h index ecce355a3..93d5e8552 100644 --- a/effects/transition.h +++ b/effects/transition.h @@ -59,8 +59,7 @@ public: static TransitionPtr Create(Clip* c, Clip* s, const EffectMeta* em, long length = 0); static TransitionPtr CreateFromMeta(Clip *c, Clip *s, const EffectMeta* em); -private slots: - void set_length_from_slider(); + private: DoubleField* length_field; }; diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index f306ec031..7efc9ad0e 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -541,23 +541,54 @@ void EffectControls::effects_area_context_menu() { } void EffectControls::delete_effects() { - // load in new clips - if (mode_ == kTransitionNone) { + ComboAction* ca = new ComboAction(); - ComboAction* ca = new ComboAction(); + for (int i=0;iIsSelected()) { + + Effect* effect_ref = open_effects_.at(i)->GetEffect(); + + if (effect_ref->meta->type == EFFECT_TYPE_EFFECT) { + + ca->append(new EffectDeleteCommand(effect_ref)); + + } else if (effect_ref->meta->type == EFFECT_TYPE_TRANSITION) { + + // Retrieve shared ptr for this transition + + Clip* attached_clip = effect_ref->parent_clip; + + TransitionPtr t = nullptr; + + if (attached_clip->opening_transition.get() == effect_ref) { + + t = attached_clip->opening_transition; + + } else if (attached_clip->closing_transition.get() == effect_ref) { + + t = attached_clip->closing_transition; + + } + + if (t == nullptr) { + + qWarning() << "Failed to delete transition, couldn't find clip link."; + + } else { + + ca->append(new DeleteTransitionCommand(t)); + + } - for (int i=0;iIsSelected()) { - ca->append(new EffectDeleteCommand(open_effects_.at(i)->GetEffect())); } } + } - if (ca->hasActions()) { - olive::UndoStack.push(ca); - panel_sequence_viewer->viewer_widget->frame_update(); - } else { - delete ca; - } + if (ca->hasActions()) { + olive::UndoStack.push(ca); + update_ui(true); + } else { + delete ca; } } @@ -594,43 +625,49 @@ void EffectControls::Load() { layout = audio_effect_layout; } - if (mode_ == kTransitionNone) { - for (int j=0;jeffects.size();j++) { + // Create a list of the effects we'll open + QVector effects_to_open; + for (int j=0;jeffects.size();j++) { + effects_to_open.append(c->effects.at(j).get()); + } + if (c->opening_transition != nullptr) { + effects_to_open.append(c->opening_transition.get()); + } + if (c->closing_transition != nullptr) { + effects_to_open.append(c->closing_transition.get()); + } - // Check if we've already opened an effect of this type before - bool already_opened = false; - for (int k=0;kGetEffect()->meta == c->effects.at(j)->meta - && !open_effects_.at(k)->IsAttachedToClip(c)) { + for (int j=0;jAddAdditionalEffect(c->effects.at(j).get()); + // Check if we've already opened an effect of this type before + bool already_opened = false; + for (int k=0;kGetEffect()->meta == effects_to_open.at(j)->meta + && !open_effects_.at(k)->IsAttachedToClip(c)) { - already_opened = true; + open_effects_.at(k)->AddAdditionalEffect(effects_to_open.at(j)); + already_opened = true; + + break; + } + } + + if (!already_opened) { + open_effect(layout, effects_to_open.at(j)); + } + + // Check if one of the open effects contains the row currently active in the graph editor. If not, we'll have + // to clear the graph editor later. + if (!graph_editor_row_is_still_active) { + for (int k=0;krow_count();k++) { + EffectRow* row = effects_to_open.at(j)->row(k); + if (row == panel_graph_editor->get_row()) { + graph_editor_row_is_still_active = true; break; } } - - if (!already_opened) { - open_effect(layout, c->effects.at(j).get()); - } - - // Check if one of the open effects contains the row currently active in the graph editor. If not, we'll have - // to clear the graph editor later. - if (!graph_editor_row_is_still_active) { - for (int k=0;keffects.at(j)->row_count();k++) { - EffectRow* row = c->effects.at(j)->row(k); - if (row == panel_graph_editor->get_row()) { - graph_editor_row_is_still_active = true; - break; - } - } - } } - } else if (mode_ == kTransitionOpening && c->opening_transition != nullptr) { - open_effect(layout, c->opening_transition.get()); - } else if (mode_ == kTransitionClosing && c->closing_transition != nullptr) { - open_effect(layout, c->closing_transition.get()); } } diff --git a/panels/panels.cpp b/panels/panels.cpp index 6d8cb3ad5..e9ca5b129 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -43,8 +43,6 @@ void update_effect_controls() { if (olive::ActiveSequence != nullptr) { selected_clips = olive::ActiveSequence->SelectedClips(); - - // TODO handle selecting transitions } panel_effect_controls->SetClips(selected_clips, mode); diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 8ec85ba97..aee029148 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -15,7 +15,26 @@ EffectUI::EffectUI(Effect* e) : { Q_ASSERT(e != nullptr); - SetTitle(e->name); + QString effect_name; + + // If this effect is actually a transition + if (e->meta->type == EFFECT_TYPE_TRANSITION) { + + // See if the transition is the clip's opening or closing transition and label it accordingly + if (e->parent_clip->opening_transition.get() == e) { + effect_name = tr("%1 (Opening)").arg(e->name); + } else { + effect_name = tr("%1 (Closing)").arg(e->name); + } + + } else { + + // Otherwise just set the title normally + effect_name = e->name; + + } + + SetTitle(effect_name); QWidget* ui = new QWidget(this); SetContents(ui); @@ -104,7 +123,7 @@ void EffectUI::AddAdditionalEffect(Effect *e) // Add multiple modifer to header label (but only once) if (!multiple_) { - QString new_title = QString(tr("%1 (multiple)")).arg(Title()); + QString new_title = tr("%1 (multiple)").arg(Title()); SetTitle(new_title); From ab3535e399768da8544cf2fbf09e18d16a1ed881 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 11:48:24 +1100 Subject: [PATCH 48/56] show only transitions in effect controls if only transitions are selected --- panels/effectcontrols.cpp | 160 +++++++++++++++++++++----------------- panels/effectcontrols.h | 7 +- panels/panels.cpp | 13 +--- timeline/sequence.cpp | 42 ++++++++++ timeline/sequence.h | 1 + ui/focusfilter.cpp | 2 +- 6 files changed, 139 insertions(+), 86 deletions(-) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 7efc9ad0e..a358691ab 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -55,8 +55,7 @@ EffectControls::EffectControls(QWidget *parent) : Panel(parent), - zoom(1), - mode_(kTransitionNone) + zoom(1) { setup_ui(); Retranslate(); @@ -145,38 +144,38 @@ void EffectControls::delete_selected_keyframes() { } void EffectControls::copy(bool del) { - if (mode_ == kTransitionNone) { - bool cleared = false; + bool cleared = false; - ComboAction* ca = nullptr; - if (del) { - ca = new ComboAction(); - } + ComboAction* ca = nullptr; + if (del) { + ca = new ComboAction(); + } - for (int i=0;iIsSelected()) { - Effect* e = open_effects_.at(i)->GetEffect(); + for (int i=0;iIsSelected()) { + Effect* e = open_effects_.at(i)->GetEffect(); - if (!cleared) { - clear_clipboard(); - cleared = true; - clipboard_type = CLIPBOARD_TYPE_EFFECT; - } + if (!cleared) { + clear_clipboard(); + cleared = true; + clipboard_type = CLIPBOARD_TYPE_EFFECT; + } - clipboard.append(e->copy(nullptr)); + clipboard.append(e->copy(nullptr)); + + if (del) { + + DeleteEffect(ca, e); - if (del) { - ca->append(new EffectDeleteCommand(e)); - } } } + } - if (del) { - if (ca->hasActions()) { - olive::UndoStack.push(ca); - } else { - delete ca; - } + if (del) { + if (ca->hasActions()) { + olive::UndoStack.push(ca); + } else { + delete ca; } } } @@ -540,47 +539,48 @@ void EffectControls::effects_area_context_menu() { menu.exec(QCursor::pos()); } -void EffectControls::delete_effects() { +void EffectControls::DeleteEffect(ComboAction* ca, Effect* effect_ref) { + if (effect_ref->meta->type == EFFECT_TYPE_EFFECT) { + + ca->append(new EffectDeleteCommand(effect_ref)); + + } else if (effect_ref->meta->type == EFFECT_TYPE_TRANSITION) { + + // Retrieve shared ptr for this transition + + Clip* attached_clip = effect_ref->parent_clip; + + TransitionPtr t = nullptr; + + if (attached_clip->opening_transition.get() == effect_ref) { + + t = attached_clip->opening_transition; + + } else if (attached_clip->closing_transition.get() == effect_ref) { + + t = attached_clip->closing_transition; + + } + + if (t == nullptr) { + + qWarning() << "Failed to delete transition, couldn't find clip link."; + + } else { + + ca->append(new DeleteTransitionCommand(t)); + + } + + } +} + +void EffectControls::DeleteSelectedEffects() { ComboAction* ca = new ComboAction(); for (int i=0;iIsSelected()) { - - Effect* effect_ref = open_effects_.at(i)->GetEffect(); - - if (effect_ref->meta->type == EFFECT_TYPE_EFFECT) { - - ca->append(new EffectDeleteCommand(effect_ref)); - - } else if (effect_ref->meta->type == EFFECT_TYPE_TRANSITION) { - - // Retrieve shared ptr for this transition - - Clip* attached_clip = effect_ref->parent_clip; - - TransitionPtr t = nullptr; - - if (attached_clip->opening_transition.get() == effect_ref) { - - t = attached_clip->opening_transition; - - } else if (attached_clip->closing_transition.get() == effect_ref) { - - t = attached_clip->closing_transition; - - } - - if (t == nullptr) { - - qWarning() << "Failed to delete transition, couldn't find clip link."; - - } else { - - ca->append(new DeleteTransitionCommand(t)); - - } - - } + DeleteEffect(ca, open_effects_.at(i)->GetEffect()); } } @@ -597,13 +597,25 @@ void EffectControls::Reload() { Load(); } -void EffectControls::SetClips(const QVector &clips, int mode) +void EffectControls::SetClips() { Clear(true); // replace clip vector - selected_clips_ = clips; - mode_ = mode; + selected_clips_ = olive::ActiveSequence->SelectedClips(); + + if (selected_clips_.isEmpty()) { + // If no clips are selected, there may be transitions that are + for (int i=0;iclips.size();i++) { + Clip* c = olive::ActiveSequence->clips.at(i).get(); + if (c != nullptr) { + if (olive::ActiveSequence->IsTransitionSelected(c->opening_transition.get()) + || olive::ActiveSequence->IsTransitionSelected(c->closing_transition.get())) { + selected_clips_.append(c); + } + } + } + } Load(); } @@ -627,13 +639,21 @@ void EffectControls::Load() { // Create a list of the effects we'll open QVector effects_to_open; - for (int j=0;jeffects.size();j++) { - effects_to_open.append(c->effects.at(j).get()); + + // Determine based on the current selections whether to load all effects or just the transitions + bool whole_clip_is_selected = c->sequence->IsClipSelected(c, true); + + if (whole_clip_is_selected) { + for (int j=0;jeffects.size();j++) { + effects_to_open.append(c->effects.at(j).get()); + } } - if (c->opening_transition != nullptr) { + if (c->opening_transition != nullptr + && (whole_clip_is_selected || c->sequence->IsTransitionSelected(c->opening_transition.get()))) { effects_to_open.append(c->opening_transition.get()); } - if (c->closing_transition != nullptr) { + if (c->closing_transition != nullptr + && (whole_clip_is_selected || c->sequence->IsTransitionSelected(c->closing_transition.get()))) { effects_to_open.append(c->closing_transition.get()); } diff --git a/panels/effectcontrols.h b/panels/effectcontrols.h index 767e57d3f..6dbe1278d 100644 --- a/panels/effectcontrols.h +++ b/panels/effectcontrols.h @@ -61,12 +61,12 @@ public: void Reload(); - void SetClips(const QVector &clips, int mode); + void SetClips(); void Clear(bool clear_cache = true); bool IsEffectSelected(Effect* e); - void delete_effects(); + void DeleteSelectedEffects(); bool is_focused(); void set_zoom(bool in); bool keyframe_focus(); @@ -110,6 +110,8 @@ private: void Load(); + void DeleteEffect(ComboAction* ca, Effect* effect_ref); + void show_effect_menu(int type, int subtype); void load_keyframes(); void open_effect(QVBoxLayout* hlayout, Effect *e); @@ -120,7 +122,6 @@ private: int effect_menu_type; int effect_menu_subtype; QString panel_name; - int mode_; QWidget* video_effect_area; QWidget* audio_effect_area; diff --git a/panels/panels.cpp b/panels/panels.cpp index e9ca5b129..0f01dee03 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -37,20 +37,9 @@ Viewer* panel_footage_viewer = nullptr; Timeline* panel_timeline = nullptr; GraphEditor* panel_graph_editor = nullptr; -void update_effect_controls() { - QVector selected_clips; - int mode = kTransitionNone; - - if (olive::ActiveSequence != nullptr) { - selected_clips = olive::ActiveSequence->SelectedClips(); - } - - panel_effect_controls->SetClips(selected_clips, mode); -} - void update_ui(bool modified) { if (modified) { - update_effect_controls(); + panel_effect_controls->SetClips(); } panel_effect_controls->update_keyframes(); panel_timeline->repaint_timeline(); diff --git a/timeline/sequence.cpp b/timeline/sequence.cpp index 6754ef4da..6ad7bc9a9 100644 --- a/timeline/sequence.cpp +++ b/timeline/sequence.cpp @@ -174,6 +174,48 @@ bool Sequence::IsClipSelected(Clip *clip, bool containing) return false; } +bool Sequence::IsTransitionSelected(Transition *t) +{ + if (t == nullptr) { + return false; + } + + Clip* c = t->parent_clip; + + int transition_track = t->parent_clip->track(); + long transition_in_point; + long transition_out_point; + + // Get positions of the transition on the timeline + + if (t == c->opening_transition.get()) { + transition_in_point = c->timeline_in(); + transition_out_point = c->timeline_in() + t->get_true_length(); + + if (t->secondary_clip != nullptr) { + transition_in_point -= t->get_true_length(); + } + } else { + transition_in_point = c->timeline_out() - t->get_true_length(); + transition_out_point = c->timeline_out(); + + if (t->secondary_clip != nullptr) { + transition_out_point += t->get_true_length(); + } + } + + // See if there's a selection matching this + for (int i=0;i= transition_out_point + && selections.at(i).track == transition_track) { + return true; + } + } + + return false; +} + void Sequence::getTrackLimits(int* video_tracks, int* audio_tracks) { int vt = 0; int at = 0; diff --git a/timeline/sequence.h b/timeline/sequence.h index 8893b1362..99c642410 100644 --- a/timeline/sequence.h +++ b/timeline/sequence.h @@ -50,6 +50,7 @@ public: bool IsClipSelected(int clip_index, bool containing); bool IsClipSelected(Clip* clip, bool containing); + bool IsTransitionSelected(Transition* t); QVector selections; long playhead; diff --git a/ui/focusfilter.cpp b/ui/focusfilter.cpp index d942279eb..b50ef0ae3 100644 --- a/ui/focusfilter.cpp +++ b/ui/focusfilter.cpp @@ -197,7 +197,7 @@ void FocusFilter::delete_function() { } else if (panel_sequence_viewer->headers->hasFocus()) { panel_sequence_viewer->headers->delete_markers(); } else if (panel_effect_controls->is_focused()) { - panel_effect_controls->delete_effects(); + panel_effect_controls->DeleteSelectedEffects(); } else if (panel_project->is_focused()) { panel_project->delete_selected_media(); } else if (panel_effect_controls->keyframe_focus()) { From a12c45dc2285b240862833e46cfae17f3859323c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 11:48:41 +1100 Subject: [PATCH 49/56] slight code enhancement --- panels/effectcontrols.cpp | 15 +-------------- timeline/sequence.cpp | 4 ++-- timeline/sequence.h | 2 +- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index a358691ab..98fd01e11 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -602,20 +602,7 @@ void EffectControls::SetClips() Clear(true); // replace clip vector - selected_clips_ = olive::ActiveSequence->SelectedClips(); - - if (selected_clips_.isEmpty()) { - // If no clips are selected, there may be transitions that are - for (int i=0;iclips.size();i++) { - Clip* c = olive::ActiveSequence->clips.at(i).get(); - if (c != nullptr) { - if (olive::ActiveSequence->IsTransitionSelected(c->opening_transition.get()) - || olive::ActiveSequence->IsTransitionSelected(c->closing_transition.get())) { - selected_clips_.append(c); - } - } - } - } + selected_clips_ = olive::ActiveSequence->SelectedClips(false); Load(); } diff --git a/timeline/sequence.cpp b/timeline/sequence.cpp index 6ad7bc9a9..5f3a69e71 100644 --- a/timeline/sequence.cpp +++ b/timeline/sequence.cpp @@ -87,13 +87,13 @@ void Sequence::RefreshClips(Media *m) { } } -QVector Sequence::SelectedClips() +QVector Sequence::SelectedClips(bool containing) { QVector selected_clips; for (int i=0;i SelectedClips(); + QVector SelectedClips(bool containing = true); QVector SelectedClipIndexes(); Effect* GetSelectedGizmo(); From 8c68a46416e9c3bbbb602af22505a69b8ddc8e60 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 12:37:36 +1100 Subject: [PATCH 50/56] limit transition values set in the effect controls --- effects/fields/doublefield.cpp | 4 +++ effects/fields/doublefield.h | 3 +++ effects/transition.cpp | 40 ++++++++++++++++++++++++++- effects/transition.h | 4 +++ ui/effectui.cpp | 2 -- ui/labelslider.h | 49 +++++++++++++++++----------------- 6 files changed, 75 insertions(+), 27 deletions(-) diff --git a/effects/fields/doublefield.cpp b/effects/fields/doublefield.cpp index 64d338587..a62836c52 100644 --- a/effects/fields/doublefield.cpp +++ b/effects/fields/doublefield.cpp @@ -23,11 +23,13 @@ double DoubleField::GetDoubleAt(double timecode) void DoubleField::SetMinimum(double minimum) { min_ = minimum; + emit MinimumChanged(min_); } void DoubleField::SetMaximum(double maximum) { max_ = maximum; + emit MaximumChanged(max_); } void DoubleField::SetDefault(double d) @@ -89,6 +91,8 @@ QWidget *DoubleField::CreateWidget(QWidget *existing) connect(ls, SIGNAL(valueChanged(double)), this, SLOT(UpdateFromWidget(double))); connect(ls, SIGNAL(clicked()), this, SIGNAL(Clicked())); connect(this, SIGNAL(EnabledChanged(bool)), ls, SLOT(setEnabled(bool))); + connect(this, SIGNAL(MaximumChanged(double)), ls, SLOT(SetMaximum(double))); + connect(this, SIGNAL(MinimumChanged(double)), ls, SLOT(SetMinimum(double))); return ls; } diff --git a/effects/fields/doublefield.h b/effects/fields/doublefield.h index 4ba53da8a..9b2882f4e 100644 --- a/effects/fields/doublefield.h +++ b/effects/fields/doublefield.h @@ -37,6 +37,9 @@ public: virtual QWidget* CreateWidget(QWidget *existing = nullptr) override; virtual void UpdateWidgetValue(QWidget* widget, double timecode) override; +signals: + void MaximumChanged(double maximum); + void MinimumChanged(double maximum); private: double min_; double max_; diff --git a/effects/transition.cpp b/effects/transition.cpp index 18b064ed7..d3a9d40cf 100644 --- a/effects/transition.cpp +++ b/effects/transition.cpp @@ -48,10 +48,12 @@ Transition::Transition(Clip *c, Clip *s, const EffectMeta* em) : EffectRow* length_row = new EffectRow(this, tr("Length"), false, false); length_field = new DoubleField(length_row, "length"); length_field->SetDefault(30); - length_field->SetMinimum(0); + length_field->SetMinimum(1); length_field->SetDisplayType(LabelSlider::FrameNumber); length_field->SetFrameRate(parent_clip->sequence == nullptr ? parent_clip->cached_frame_rate() : parent_clip->sequence->frame_rate); + + connect(length_field, SIGNAL(Changed()), this, SLOT(UpdateMaximumLength())); } TransitionPtr Transition::copy(Clip *c, Clip *s) { @@ -119,6 +121,42 @@ TransitionPtr Transition::CreateFromMeta(Clip* c, Clip* s, const EffectMeta* em) return nullptr; } +void Transition::UpdateMaximumLength() +{ + // Get the maximum area this transition can occupy on the clip + long maximum_length = GetMaximumEmptySpaceOnClip(parent_clip); + + // If this clip is a shared transition, get the maximum area this can occupy on the other clip too + if (secondary_clip != nullptr) { + long secondary_max_length = GetMaximumEmptySpaceOnClip(secondary_clip); + + maximum_length = qMin(secondary_max_length, maximum_length); + } + + length_field->SetMaximum(maximum_length); +} + +long Transition::GetMaximumEmptySpaceOnClip(Clip *c) +{ + long maximum_transition_length = c->length(); + + Transition* opposite_transition; + + // See if this clip has a transition on the opposite side that we need to account for + if (c->opening_transition.get() == this) { + opposite_transition = c->closing_transition.get(); + } else { + opposite_transition = c->opening_transition.get(); + } + + // If is does, subtract the maximum length by the transition's length + if (opposite_transition != nullptr) { + maximum_transition_length -= opposite_transition->get_true_length(); + } + + return maximum_transition_length; +} + TransitionPtr Transition::Create(Clip* c, Clip* s, const EffectMeta* em, long length) { TransitionPtr t(CreateFromMeta(c, s, em)); if (t != nullptr) { diff --git a/effects/transition.h b/effects/transition.h index 93d5e8552..8895d9dd7 100644 --- a/effects/transition.h +++ b/effects/transition.h @@ -62,6 +62,10 @@ public: private: DoubleField* length_field; + +private slots: + void UpdateMaximumLength(); + long GetMaximumEmptySpaceOnClip(Clip* c); }; #endif // TRANSITION_H diff --git a/ui/effectui.cpp b/ui/effectui.cpp index aee029148..11284d092 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -143,8 +143,6 @@ void EffectUI::AddAdditionalEffect(Effect *e) for (int j=0;jFieldCount();j++) { - EffectField* field = row->Field(j); - // Attach existing field widget to this effect's field e->row(i)->Field(j)->CreateWidget(Widget(i, j)); diff --git a/ui/labelslider.h b/ui/labelslider.h index c1402d1de..9727c26d1 100644 --- a/ui/labelslider.h +++ b/ui/labelslider.h @@ -61,30 +61,6 @@ public: */ void SetDefault(double v); - /** - * @brief Set the minimum value - * - * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than - * the minimum, it will automatically snap to the minimum. - * - * @param v - * - * Value to set as minimum - */ - void SetMinimum(double v); - - /** - * @brief Set the maximum value - * - * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than - * the maximum, it will automatically snap to the maximum. - * - * @param v - * - * Value to set as maximum - */ - void SetMaximum(double v); - /** * @brief Returns the internal value as a double * @return The internal value. This will not respect the `display_type`, i.e. 100% will return as 1.0, 12dB will @@ -145,6 +121,31 @@ public: * Defaults to 1 */ void SetDecimalPlaces(int places); +public slots: + /** + * @brief Set the minimum value + * + * If a minimum value is set, the value will never go below it. If the user manually sets a value lower than + * the minimum, it will automatically snap to the minimum. + * + * @param v + * + * Value to set as minimum + */ + void SetMinimum(double v); + + /** + * @brief Set the maximum value + * + * If a maximum value is set, the value will never go above it. If the user manually sets a value higher than + * the maximum, it will automatically snap to the maximum. + * + * @param v + * + * Value to set as maximum + */ + void SetMaximum(double v); + protected: void mousePressEvent(QMouseEvent *ev); void mouseMoveEvent(QMouseEvent *ev); From 1f21fdac8a5141a30c5edde24e9814ce13271661 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 12:41:43 +1100 Subject: [PATCH 51/56] initialize enabled value --- effects/effect.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index d5ae333d6..4b1ff407a 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -123,7 +123,8 @@ Effect::Effect(Clip* c, const EffectMeta *em) : texture(nullptr), isOpen(false), bound(false), - iterations(1) + iterations(1), + enabled_(true) { if (em != nullptr) { // set up UI from effect file From f1bc01ec723c587a8572e523bff74b942a7c0dd7 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 12:55:28 +1100 Subject: [PATCH 52/56] better transition labelling in effect controls --- timeline/clip.cpp | 9 +++++++++ timeline/clip.h | 1 + timeline/sequence.h | 4 ++-- ui/effectui.cpp | 36 +++++++++++++++++++++++++++++++++--- 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/timeline/clip.cpp b/timeline/clip.cpp index 0a8a9d6b9..5b4311de6 100644 --- a/timeline/clip.cpp +++ b/timeline/clip.cpp @@ -102,6 +102,15 @@ bool Clip::IsActiveAt(long timecode) && timecode - timeline_in(true) + clip_in(true) < media_length(); } +bool Clip::IsSelected(bool containing) +{ + if (this->sequence == nullptr) { + return false; + } + + return this->sequence->IsClipSelected(this, containing); +} + const QColor &Clip::color() { return color_; diff --git a/timeline/clip.h b/timeline/clip.h index cf8435966..8e6e94914 100644 --- a/timeline/clip.h +++ b/timeline/clip.h @@ -59,6 +59,7 @@ public: ClipPtr copy(Sequence *s); bool IsActiveAt(long timecode); + bool IsSelected(bool containing = true); const QColor& color(); void set_color(int r, int g, int b); diff --git a/timeline/sequence.h b/timeline/sequence.h index f4e2e5518..559564e3b 100644 --- a/timeline/sequence.h +++ b/timeline/sequence.h @@ -48,8 +48,8 @@ public: Effect* GetSelectedGizmo(); - bool IsClipSelected(int clip_index, bool containing); - bool IsClipSelected(Clip* clip, bool containing); + bool IsClipSelected(int clip_index, bool containing = true); + bool IsClipSelected(Clip* clip, bool containing = true); bool IsTransitionSelected(Transition* t); QVector selections; diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 11284d092..836a4836e 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -20,11 +20,41 @@ EffectUI::EffectUI(Effect* e) : // If this effect is actually a transition if (e->meta->type == EFFECT_TYPE_TRANSITION) { + Transition* t = static_cast(e); + + // Since effects can have two clip attachments, find out which one is selected + Clip* selected_clip = t->parent_clip; + bool both_selected = false; + + // Check if this is a shared transition + if (t->secondary_clip != nullptr) { + + // Check which clips are selected + if (t->secondary_clip->IsSelected()) { + + selected_clip = t->secondary_clip; + + if (t->parent_clip->IsSelected()) { + // Both clips are selected + both_selected = true; + } + + } else if (!t->parent_clip->IsSelected()) { + + // Neither are selected, but the naming scheme (no "opening" or "closing" modifier) will be the same + both_selected = true; + + } + + } + // See if the transition is the clip's opening or closing transition and label it accordingly - if (e->parent_clip->opening_transition.get() == e) { - effect_name = tr("%1 (Opening)").arg(e->name); + if (both_selected) { + effect_name = t->name; + } else if (selected_clip->opening_transition.get() == t) { + effect_name = tr("%1 (Opening)").arg(t->name); } else { - effect_name = tr("%1 (Closing)").arg(e->name); + effect_name = tr("%1 (Closing)").arg(t->name); } } else { From 644b14707a303aaa0c0ae40376ae4bb2e541cc3d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 13:01:58 +1100 Subject: [PATCH 53/56] replaced sequence::isclipselected with clip::isselected --- panels/effectcontrols.cpp | 2 +- panels/timeline.cpp | 12 ++++++------ ui/timelinewidget.cpp | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 98fd01e11..5132fe333 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -628,7 +628,7 @@ void EffectControls::Load() { QVector effects_to_open; // Determine based on the current selections whether to load all effects or just the transitions - bool whole_clip_is_selected = c->sequence->IsClipSelected(c, true); + bool whole_clip_is_selected = c->IsSelected(); if (whole_clip_is_selected) { for (int j=0;jeffects.size();j++) { diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 9a3732db1..f10941a4e 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -371,7 +371,7 @@ void Timeline::add_transition() { for (int i=0;iclips.size();i++) { Clip* c = olive::ActiveSequence->clips.at(i).get(); - if (c != nullptr && olive::ActiveSequence->IsClipSelected(c, true)) { + if (c != nullptr && c->IsSelected()) { int transition_to_add = (c->track() < 0) ? TRANSITION_INTERNAL_CROSSDISSOLVE : TRANSITION_INTERNAL_LINEARFADE; if (c->opening_transition == nullptr) { ca->append(new AddTransitionCommand(c, @@ -944,14 +944,14 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool if (relink) { pre_clips.append(clip); - bool original_clip_is_selected = olive::ActiveSequence->IsClipSelected(c, true); + bool original_clip_is_selected = c->IsSelected(); // find linked clips of old clip for (int i=0;ilinked.size();i++) { int l = c->linked.at(i); if (!split_cache.contains(l)) { Clip* link = olive::ActiveSequence->clips.at(l).get(); - if ((original_clip_is_selected && olive::ActiveSequence->IsClipSelected(link, true)) || !original_clip_is_selected) { + if ((original_clip_is_selected && link->IsSelected()) || !original_clip_is_selected) { split_cache.append(l); ClipPtr s = split_clip(ca, true, l, frame); if (s != nullptr) { @@ -1487,7 +1487,7 @@ void Timeline::split_at_playhead() { QVector post_clips; for (int j=0;jclips.size();j++) { Clip* clip = olive::ActiveSequence->clips.at(j).get(); - if (clip != nullptr && olive::ActiveSequence->IsClipSelected(clip, true)) { + if (clip != nullptr && clip->IsSelected()) { ClipPtr s = split_clip(ca, true, j, olive::ActiveSequence->playhead); if (s != nullptr) { pre_clips.append(j); @@ -1630,7 +1630,7 @@ void Timeline::set_marker() { for (int i=0;iclips.size();i++) { Clip* c = olive::ActiveSequence->clips.at(i).get(); if (c != nullptr - && olive::ActiveSequence->IsClipSelected(c, true)) { + && c->IsSelected()) { // only add markers if the playhead is inside the clip if (olive::ActiveSequence->playhead >= c->timeline_in() @@ -1684,7 +1684,7 @@ void Timeline::toggle_links() { command->s = olive::ActiveSequence.get(); for (int i=0;iclips.size();i++) { Clip* c = olive::ActiveSequence->clips.at(i).get(); - if (c != nullptr && olive::ActiveSequence->IsClipSelected(c, true)) { + if (c != nullptr && c->IsSelected()) { if (!command->clips.contains(i)) command->clips.append(i); if (c->linked.size() > 0) { diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 01252a49f..0db9e46d0 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -656,7 +656,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { if (hovered_clip >= 0) { Clip* clip = olive::ActiveSequence->clips.at(hovered_clip).get(); - if (olive::ActiveSequence->IsClipSelected(clip, true)) { + if (clip->IsSelected()) { if (shift) { @@ -759,7 +759,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { Clip* link = olive::ActiveSequence->clips.at(clip->linked.at(i)).get(); // check if the clip is already selected - if (!olive::ActiveSequence->IsClipSelected(link, true)) { + if (!link->IsSelected()) { Selection ss; ss.in = link->timeline_in(); ss.out = link->timeline_out(); @@ -2065,7 +2065,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { Clip* c = olive::ActiveSequence->clips.at(j).get(); - if (c != nullptr && olive::ActiveSequence->IsClipSelected(c, false)) { + if (c != nullptr && c->IsSelected(false)) { // loop through linked clips for (int k=0;klinked.size();k++) { @@ -2195,7 +2195,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { // if a transition isn't selected, check if the whole clip is if (!add) { - add = olive::ActiveSequence->IsClipSelected(c, true); + add = c->IsSelected(); } if (add) { From 9b86bc4b32c1787aea2b04c860f933798d67809c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 15 Mar 2019 22:13:12 +1100 Subject: [PATCH 54/56] documented effectfield --- Doxyfile | 3 +- effects/effectfield.cpp | 4 +- effects/effectfield.h | 433 +++++++++++++++++++++++++++++++++++++++- effects/effectfields.h | 6 + 4 files changed, 434 insertions(+), 12 deletions(-) diff --git a/Doxyfile b/Doxyfile index c717922fd..2df85e372 100644 --- a/Doxyfile +++ b/Doxyfile @@ -914,7 +914,8 @@ EXCLUDE_SYMLINKS = NO # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = */.git/* \ - */docs/* + */docs/* \ + */include/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index 0321e8d76..aa0dbbef6 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -67,8 +67,6 @@ EffectField::EffectField(EffectRow* parent, const QString &i, EffectFieldType t) connect(this, SIGNAL(Changed()), parent->GetParentEffect(), SLOT(FieldChanged())); } -EffectField::~EffectField() {} - EffectRow *EffectField::GetParentRow() { return static_cast(parent()); @@ -97,7 +95,7 @@ QString EffectField::ConvertValueToString(const QVariant &v) QWidget *EffectField::CreateWidget(QWidget *existing) { - return (existing == nullptr) ? new QLabel(tr("(Invalid field)")) : existing; + Q_ASSERT(false); } void EffectField::UpdateWidgetValue(QWidget *, double) {} diff --git a/effects/effectfield.h b/effects/effectfield.h index af3e236e6..9d5dae487 100644 --- a/effects/effectfield.h +++ b/effects/effectfield.h @@ -32,69 +32,486 @@ class EffectRow; class ComboAction; +/** + * @brief The EffectField class + * + * Any user-interactive element of an Effect. Usually a parameter that modifies the effect output, but sometimes just + * a UI object that performs some other function (e.g. LabelField and ButtonField). + * + * EffectField provides a largely abstract interface for Effect classes to pull information from. The class itself + * handles keyframing between linear, bezier, and hold interpolation accessible through GetValueAt(). This class + * is abstract, and therefore never intended to be used on its own. Instead you should always use a derived class. + * + * EffectField objects are *not* UI objects on their own. Instead, they're largely a system of values that can change + * over time. For a widget that the user can use to edit/modify these values, use CreateWidget(). + * + * Derived classes are expected to override at least CreateWidget() to create a visual interactive widget corresponding + * to the field. If this + * field is a value used in the Effect (as most will be), UpdateWidgetValue() should also be overridden to display the + * correct value for this field as the user moves around the Timeline. + * + * If the field is intended to be saved and loaded from Olive project files (as most will be), ConvertStringToValue() + * and ConvertValueToString() may also have to be overridden depending on how the derived class's data works. + */ class EffectField : public QObject { Q_OBJECT public: + /** + * @brief The EffectFieldType enum + * + * Predetermined types of fields. Used throughout Olive to identify what kind of data to expect from GetValueAt(). + * + * This enum is also currently used to match an external XML effect's fields with the correct derived class (e.g. + * EFFECT_FIELD_DOUBLE matches to DoubleField). + */ enum EffectFieldType { + /** Values are doubles. Also corresponds to DoubleField. */ EFFECT_FIELD_DOUBLE, + + /** Values are colors. Also corresponds to ColorField. */ EFFECT_FIELD_COLOR, + + /** Values are strings. Also corresponds to StringField. */ EFFECT_FIELD_STRING, + + /** Values are booleans. Also corresponds to BoolField. */ EFFECT_FIELD_BOOL, + + /** Values are arbitrary data. Also corresponds to ComboField. */ EFFECT_FIELD_COMBO, + + /** Values are font family names (in string). Also corresponds to FontField. */ EFFECT_FIELD_FONT, + + /** Values are filenames (in string). Also corresponds to FileField. */ EFFECT_FIELD_FILE, + + /** Values is a UI object with no data. Corresponds to nothing. */ EFFECT_FIELD_UI }; + /** + * @brief EffectField Constructor + * + * Creates a new EffectField object. + * + * @param parent + * + * The EffectRow to add this field to. This must be a valid EffectRow. The EffectRow takes ownership of the field + * using the QObject parent/child system to automate memory management. EffectFields are never expected + * to change parent during their lifetime. + * + * @param i + * + * Field ID. Must be non-empty. Must also be unique within this Effect. Used for saving/loading values into project + * files so that if ordering of fields are changed, or fields are added/removed from Effects later in development, + * saved values in project files will still link with the correct field. Also used as the uniform variable name + * in GLSL shaders. + * + * @param t + * + * The type of data contained within this field. This is expected to be filled by a derived class. + */ EffectField(EffectRow* parent, const QString& i, EffectFieldType t); - ~EffectField(); + /** + * @brief Get the EffectRow that this field is a member of. + * + * Equivalent to `static_cast(EffectField::parent())` + * + * @return + * + * The EffectRow that this field is a member of. + */ EffectRow* GetParentRow(); + /** + * @brief Get the type of data to expect from this field + * + * @return + * + * A member of the EffectFieldType enum. + */ const EffectFieldType& type(); + + /** + * @brief Get the unique identifier of this field set in the constructor + * + * Mostly used for saving/loading or interacting with GLSL-based shader effects (see EffectField() for more details). + * + * @return + */ const QString& id(); + /** + * @brief Get the value of this field at a given timecode + * + * EffectFields are designed to be keyframable, meaning the user can make the values change over the course of the + * Sequence. This is the main function used through Olive to retrieve what value this field will be at a given time. + * + * A common use case for this function would be EffectField::GetValueAt(EffectField::Now()), which will automatically + * retrieve the timecode at the current playhead. + * + * If the parent EffectRow is NOT keyframing, this function will simply return persistent_data_. If it IS keyframing, + * this will use the values in `keyframes` to determine what value should be specifically at this time. + * (bezier or linear interpolating it between values if necessary). Therefore this function should almost always be + * used to retrieve data from this field as the value will always be correct for the given time. + * + * @param timecode + * + * The time to retrieve the value in clip/media seconds (e.g. 0.0 is the very start of the media, 1.0 is one second + * into the media). + * + * @return + * + * A QVariant representation of the value at the given timecode. + */ QVariant GetValueAt(double timecode); + + /** + * @brief Set the value of this field at a given timecode + * + * EffectFields are designed to be keyframable, meaning the user can make the values change over the course of the + * Sequence. This is the main function used through Olive to set what value this field will be at a given time. + * + * If the parent EffectRow is keyframing, this function will determine whether a keyframe exists at this time already. + * If it does, it will change the value at that keyframe to `value`. Otherwise, it'll create a new keyframe at the + * specified `time` with the specified `value`. + * + * If the parent EffectRow is not keyframing, the data is simply stored in `persistent_data_`. + * + * When constructing an Effect + * + * @param time + * + * The time to retrieve the value at in clip/media seconds (e.g. 0.0 is the very start of the media, 1.0 is one + * second into the media). + * + * @param value + * + * The QVariant value to set at this time. + */ void SetValueAt(double time, const QVariant& value); + /** + * @brief Get the current clip/media time + * + * A convenience function that can be plugged into GetValueAt() to get the value wherever the appropriate Sequence's + * playhead it. + * + * @return + * + * Current clip/media time in seconds. + */ double Now(); - long NowInFrames(); + /** + * @brief Set up keyframing on this field + * + * This should always be called if the user is enabling/disabling keyframing on the parent row. This function will + * move data between persistent_data_ and keyframes depending on whether keyframing is being enabled or disabled. + * + * If keyframing is getting ENABLED, this function will create the first keyframe automatically at the current time + * using the current value in persistent_data_. + * + * If keyframing is getting DISABLED, persistent_data_ is set to the current value at this time (GetValueAt(Now())) + * and delete all current keyframes. + * + * @param enabled + * + * TRUE if keyframing is getting enabled. + * + * @param ca + * + * A valid ComboAction object. It's expected that this function will be part of a larger action to enable/disable + * keyframing on the parent EffectRow, so this function will add commands to this ComboAction. + */ void PrepareDataForKeyframing(bool enabled, ComboAction* ca); + /** + * @brief Get field's column span + * + * Used whenever constructing the effect's UI. EffectFields are visually laid out in a table, and some widgets can + * be set to take up multiple columns for a better visual flow. + * + * @return + * + * The current column span. + */ int GetColumnSpan(); + + /** + * @brief Set field's column span + * + * Used whenever constructing the effect's UI. EffectFields are visually laid out in a table, and some widgets can + * be set to take up multiple columns for a better visual flow. + * + * @param i + * + * The column span to set on this field. + */ void SetColumnSpan(int i); - virtual QVariant ConvertStringToValue(const QString& s); + /** + * @brief Convert a value from this field to a string + * + * When saving effect data to a project file, the data needs to be converted to a string format for saving in XML. + * The needs of this string representation may differ depending on the needs of the derived class, therefore you + * derived classes may need to override it. + * + * Default behavior is a simple QVariant <-> QString conversion, which should suffice in most cases. + * + * @param v + * + * The QVariant data (retrieved from this field) to convert to string + * + * @return + * + * A string representation of the QVariant data provided. + */ virtual QString ConvertValueToString(const QVariant& v); - virtual QWidget* CreateWidget(QWidget* existing = nullptr); - virtual void UpdateWidgetValue(QWidget* widget, double); + /** + * @brief Convert a string to a value appropriate for this field + * + * This function is the inverse of ConvertValueToString(), converting a string back to field data. + * + * @param s + * + * The string to convert to data. + * + * @return + * + * QVariant data converted from the provided string. + */ + virtual QVariant ConvertStringToValue(const QString& s); + + /** + * @brief Create a widget for the user to interact with this field + * + * EffectField objects are *not* UI objects on their own. Instead, they're largely a system of values that can change + * over time. This function creates a QWidget object that can be placed somewhere in the UI so the user can + * interact with and change the data in this field. + * + * This function must be overridden by derived classes in order to create a widget that appropriate for that field's + * data. The derived class is also responsible for + * connecting signals like EnabledChanged(), Clicked(), and any other data that needs to be transferred between the + * widget and the field (setting up the signals and slots to do so). The field does NOT retain ownership (or any + * reference for that matter) to widgets it creates, + * so keeping the widget and field up to date with each other relies solely on setting up signals and slots. + * Infinite widgets can be created from a single field and used throughout Olive this way. + * + * Ownership is passed to the caller, and therefore the caller is responsible for freeing it. + * + * @param existing + * + * Olive allows multiple effects to attach to one UI layout. Pass a QWidget to this parameter (instead of nullptr) + * to attach this field additionally to the widget's signals/slots without creating a new one. The QWidget must be a + * widget previously created from the same derived class type or the result is undefined. + * + * @return + * + * A new QWidget object for this EffectField, or the same QWidget passed to `existing` if one was specified. + */ + virtual QWidget* CreateWidget(QWidget* existing = nullptr) = 0; + + /** + * @brief Update a widget created by CreateWidget() using the value at a given time + * + * Use this function to update a QWidget (obtained from CreateWidget()) with the correct value from the field at a + * given time. + * + * Since only the derived classes know what type of QWidget it created in CreateWidget() and how to work with them, + * derived classes are also expected to override this function if the field is an active value used in the Effect + * that should visually update as the user moves around the Timeline. However if the field does NOT need to update + * live (e.g. the field is just a UI wrapper like LabelField or ButtonField), this function does not need to be + * overridden as the default behavior (to do nothing) will suffice in those cases. + * + * @param widget + * + * The QWidget to set the value of (must be a QWidget obtained from CreateWidget() or the behavior is undefined). + * + * @param timecode + * + * The time in clip/media seconds to retrieve data from. + */ + virtual void UpdateWidgetValue(QWidget* widget, double timecode); + + /** + * @brief Get the correct X position/time value of a bezier keyframe's handles + * + * Retrieves the X value (time value) of a bezier keyframe's handles. Internally, the handles' X values are allowed + * to be arbitrary values. This however can lead to inadvertently creating impossible bezier curves (ones that, for + * example, mathematically loop over each other, but obviously a field can't have two values at the same time). + * + * This function returns the keyframe handles' X values adjusted to prevent this from happening. All calculations + * are consistent (i.e. the post handle of one keyframe will be adjusted the same way as the pre handle of the + * keyframe before it). It's recommended to always use this function to retrieve keyframe handle X values. + * + * @param key + * + * Index of the keyframe (in `keyframes`) to retrieve the handle position from. + * + * @param post + * + * FALSE to retrieve the "pre" handle (handle to the left of the keyframe), TRUE to retrieve the "post" handle + * (handle to the right of the keyframe). + * + * @return + * + * The adjusted X value of that keyframe handle. + */ double GetValidKeyframeHandlePosition(int key, bool post); + /** + * @brief Return whether this field is enabled or not + * + * @return + * + * TRUE if this field is enabled. + */ bool IsEnabled(); + + /** + * @brief Set the enabled state of this field + * @param e + * + * TRUE to enable this field, FALSE to disable it. + */ void SetEnabled(bool e); + /** + * @brief Persistent data object + * + * If the parent EffectRow is not keyframing, all field data is stored and retrieved here. If the row IS keyframing, + * this variable goes basically unused unless `keyframes` is empty. + * + * NOTE: It is NOT recommended to access this variable directly. Use GetValueAt() instead. + */ QVariant persistent_data_; + + /** + * @brief Keyframe array + * + * Contains all data about this field's keyframes, from the keyframe times, to their data, to their type (linear, + * bezier, or hold), to the bezier handles (if using bezier). If the row is not keyframing, this array is never used + * (`persistent_data_` is used instead). If it is, this array will always be used unless the array is empty, in which + * case `persistent_data_` will be used again. + */ QVector keyframes; signals: + /** + * @brief Changed signal + * + * Emitted whenever SetValueAt() is called in order to trigger a UI update and Viewer repaint. Note this is NOT + * triggered as the value changes from keyframing. Only when the user themselves triggers a change. + */ void Changed(); + + /** + * @brief Clicked signal + * + * Emitted when the user clicks on a QWidget attached to this field. Derived classes should connect this to the + * clicked signal of any QWidget's created (or attached) in CreateWidget(). + */ void Clicked(); + /** + * @brief Enable change state signal + * + * Emitted when the field's enabled state is changed through SetEnabled(). Derived classes should connect this to the + * setEnabled() slot of any QWidget's created (or attached) in CreateWidget(). + */ void EnabledChanged(bool); private: + /** + * @brief Internal type variable set in the constructor. Access with type(). + */ EffectFieldType type_; + + /** + * @brief Internal unique identifier for this field set in the constructor. Access with id(). + */ QString id_; + /** + * @brief Used by GetValueAt() to determine whether to use keyframe data or persistent data + * @return + * + * TRUE if this keyframe data should be retrieved, FALSE if persistent data should be retrieved + */ bool HasKeyframes(); - double frameToTimecode(long frame); - long timecodeToFrame(double timecode); - void get_keyframe_data(double timecode, int& before, int& after, double& d); + /** + * @brief Convert clip time in frames to clip time in seconds + * + * @param frame + * + * Clip time in frames + * + * @return + * + * Clip time in seconds + */ + double FrameToSeconds(long frame); + + /** + * @brief Convert clip time in seconds to clip time in frames + * + * @param seconds + * + * Clip time in seconds + * + * @return + * + * Clip time in frames + */ + long SecondsToFrame(double seconds); + + /** + * @brief Internal function for determining where we are between the available keyframes + * + * @param timecode + * + * Timecode to get keyframe data at + * + * @param before + * + * The index (in the keyframes array) in the keyframe prior to this timecode. + * + * @param after + * + * The index (in the keyframes array) in the keyframe after this timecode. + * + * @param d + * + * The progress between the `before` keyframe and `after` keyframe from 0.0 to 1.0. + */ + void GetKeyframeData(double timecode, int& before, int& after, double& d); + + /** + * @brief Retrieve the current clip as a frame number + * + * Same as Now() but retrieves the value as a frame number (in the appropriate Sequence's frame rate) instead of + * seconds. + * + * @return + * + * The current clip time in frames + */ + long NowInFrames(); + + /** + * @brief Internal enabled value + */ bool enabled_; + + /** + * @brief Internal column span value + */ int colspan_; }; diff --git a/effects/effectfields.h b/effects/effectfields.h index 1c8e687e2..1a6e1777a 100644 --- a/effects/effectfields.h +++ b/effects/effectfields.h @@ -1,6 +1,12 @@ #ifndef EFFECTFIELDS_H #define EFFECTFIELDS_H +/** + + A simple convenience header for including all the available EffectField derivations. + + */ + #include "fields/boolfield.h" #include "fields/buttonfield.h" #include "fields/colorfield.h" From 7d80c11d3710167b135db6ec63f6b94fdbc4bef9 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 16 Mar 2019 16:21:52 +1100 Subject: [PATCH 55/56] documented EffectUI --- effects/effectfield.cpp | 30 +++--- effects/effectrow.cpp | 21 ++--- effects/effectrow.h | 189 +++++++++++++++++++++++++++++++++++++- panels/effectcontrols.cpp | 20 ++-- ui/effectui.cpp | 10 +- ui/effectui.h | 164 ++++++++++++++++++++++++++++++++- 6 files changed, 383 insertions(+), 51 deletions(-) diff --git a/effects/effectfield.cpp b/effects/effectfield.cpp index aa0dbbef6..86886d3ad 100644 --- a/effects/effectfield.cpp +++ b/effects/effectfield.cpp @@ -93,11 +93,6 @@ QString EffectField::ConvertValueToString(const QVariant &v) return v.toString(); } -QWidget *EffectField::CreateWidget(QWidget *existing) -{ - Q_ASSERT(false); -} - void EffectField::UpdateWidgetValue(QWidget *, double) {} QVariant EffectField::GetValueAt(double timecode) @@ -106,7 +101,7 @@ QVariant EffectField::GetValueAt(double timecode) int before_keyframe; int after_keyframe; double progress; - get_keyframe_data(timecode, before_keyframe, after_keyframe, progress); + GetKeyframeData(timecode, before_keyframe, after_keyframe, progress); const QVariant& before_data = keyframes.at(before_keyframe).data; switch (type_) { @@ -133,7 +128,7 @@ QVariant EffectField::GetValueAt(double timecode) if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) { // cubic bezier - double t = cubic_t_from_x(timecodeToFrame(timecode), + double t = cubic_t_from_x(SecondsToFrame(timecode), before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), @@ -148,7 +143,7 @@ QVariant EffectField::GetValueAt(double timecode) } else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier // last keyframe is the bezier one - double t = quad_t_from_x(timecodeToFrame(timecode), + double t = quad_t_from_x(SecondsToFrame(timecode), before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time); @@ -160,7 +155,7 @@ QVariant EffectField::GetValueAt(double timecode) } else { // this keyframe is the bezier one - double t = quad_t_from_x(timecodeToFrame(timecode), + double t = quad_t_from_x(SecondsToFrame(timecode), before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time); @@ -215,7 +210,7 @@ void EffectField::SetValueAt(double time, const QVariant &value) // Create keyframe here // Convert seconds timecode to frame - long frame_timecode = timecodeToFrame(time); + long frame_timecode = SecondsToFrame(time); // Check array if a keyframe at this time already exists int keyframe_index = -1; @@ -345,20 +340,20 @@ double EffectField::GetValidKeyframeHandlePosition(int key, bool post) { return adjusted_key; } -double EffectField::frameToTimecode(long frame) { +double EffectField::FrameToSeconds(long frame) { return (double(frame) / GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); } -long EffectField::timecodeToFrame(double timecode) { - return qRound(timecode * GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); +long EffectField::SecondsToFrame(double seconds) { + return qRound(seconds * GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate); } -void EffectField::get_keyframe_data(double timecode, int &before, int &after, double &progress) { +void EffectField::GetKeyframeData(double timecode, int &before, int &after, double &progress) { int before_keyframe_index = -1; int after_keyframe_index = -1; long before_keyframe_time = LONG_MIN; long after_keyframe_time = LONG_MAX; - long frame = timecodeToFrame(timecode); + long frame = SecondsToFrame(timecode); for (int i=0;i -1 && after_keyframe_index > -1)) { + if ((type_ == EFFECT_FIELD_DOUBLE || type_ == EFFECT_FIELD_COLOR) + && (before_keyframe_index > -1 && after_keyframe_index > -1)) { // interpolate before = before_keyframe_index; after = after_keyframe_index; - progress = (timecode-frameToTimecode(before_keyframe_time))/(frameToTimecode(after_keyframe_time)-frameToTimecode(before_keyframe_time)); + progress = (timecode-FrameToSeconds(before_keyframe_time))/(FrameToSeconds(after_keyframe_time)-FrameToSeconds(before_keyframe_time)); } else if (before_keyframe_index > -1) { before = before_keyframe_index; after = before_keyframe_index; diff --git a/effects/effectrow.cpp b/effects/effectrow.cpp index d61980fa2..06b998d66 100644 --- a/effects/effectrow.cpp +++ b/effects/effectrow.cpp @@ -60,6 +60,11 @@ bool EffectRow::IsKeyframing() { } void EffectRow::SetKeyframingInternal(bool b) { + // No need to run this function if the keyframing state isn't actually changing. + if (b == keyframing_) { + return; + } + if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) { keyframing_ = b; emit KeyframingSetChanged(keyframing_); @@ -77,6 +82,10 @@ bool EffectRow::IsKeyframable() } void EffectRow::SetKeyframingEnabled(bool enabled) { + if (enabled == keyframing_) { + return; + } + if (enabled) { ComboAction* ca = new ComboAction(); @@ -257,18 +266,6 @@ void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) { panel_effect_controls->update_keyframes(); } -void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) { - for (int j=0;jkeyframes.size();i++) { - if (f->keyframes.at(i).time == time) { - ca->append(new KeyframeDelete(f, i)); - break; - } - } - } -} - Effect *EffectRow::GetParentEffect() { return static_cast(parent()); diff --git a/effects/effectrow.h b/effects/effectrow.h index 71df69f15..723a368ab 100644 --- a/effects/effectrow.h +++ b/effects/effectrow.h @@ -36,43 +36,226 @@ class ClickableLabel; #include "effectfields.h" +/** + * @brief The EffectRow class + * + * Primarily a way of grouping EffectField objects together. As UI objects, Effects are largely formatted as a table + * and you can think of EffectRows as the rows of the table and EffectFields as the columns. + * + * Within Olive, keyframing is enabled on the EffectRow (rather than individual EffectFields) so all attached fields + * will be keyframed together. + * + * Unlike EffectField, there's no reason to derive from EffectRow as it's simply a container of fields and a few + * keyframe functions. + */ class EffectRow : public QObject { Q_OBJECT public: + /** + * @brief EffectRow Constructor + * + * @param parent + * + * Every EffectRow object must be attached to a valid Effect object. The Effect object takes ownership of the + * EffectRow and automatically frees it through the QObject parent/child system. EffectRows are never intended to + * change parents throughout their lifetimes. + * + * @param n + * + * Row name. This is not used as an internal identifier, it's just for the user interface, so it can be translated + * with no issue. + * + * @param savable + * + * Whether the fields in this row should be saved to the project file. This is true by default. If the row contains + * non-value UI widgets, setting this to false is recommended. + * + * @param keyframable + * + * Whether keyframing can be enabled on this row or not. This is true by default. Some values you may want to prevent + * the user from keyframing (e.g. the filename of a VST plugin), which can be done by setting this to false. + */ EffectRow(Effect* parent, const QString& n, bool savable = true, bool keyframable = true); + /** + * @brief Add a field to this row + * + * Ownership of the EffectField is transferred to this row and the row will free its memory. In the Effect's UI, this + * will add the field to an additional column. + * + * @param Field + * + * The field to add to this row. + */ void AddField(EffectField* Field); + /** + * @brief Retrieve the EffectField at this index. Must be less than FieldCount(). + * + * @param i + * + * Index to retrieve the EffectField at. + * + * @return + * + * EffectField at the provided index. + */ EffectField* Field(int i); - int FieldCount(); - void SetKeyframeOnAllFields(ComboAction *ca); - void delete_keyframe_at_time(ComboAction *ca, long time); + /** + * @brief Number of fields currently contained in this row. + * + * @return The number of fields currently contained in this row as an integer. Any field index (retrieved with + * Field()) is guaranteed to be valid >= 0 and < FieldCount(). + */ + int FieldCount(); + + /** + * @brief Set a keyframe at the current playhead on all fields contained within this row + * + * @param ca + * + * The ComboAction to add this action to. This may not be nullptr. + */ + void SetKeyframeOnAllFields(ComboAction *ca); + + /** + * @brief Get parent Effect + * + * Equivalent to `static_cast(parent())`. + * + * @return The parent Effect object that this row is attached to. + */ Effect* GetParentEffect(); + /** + * @brief Return the row's name + * + * @return The name specified in the constructor as a QString + */ const QString& name(); + /** + * @brief Get whether this row is keyframing or not + * + * @return True if this row is keyframing. + */ bool IsKeyframing(); + + /** + * @brief Set whether this row is keyframing or not. + * + * It's not recommended to use this function for any user-initiated keyframe setting change as it doesn't create any + * undoable actions. Use SetKeyframingEnabled() instead for a user-friendly variant. + */ void SetKeyframingInternal(bool); + /** + * @brief Get whether this row should be saved into a project file or not + * + * @return True if this row should be saved. This value is set in the constructor. + */ bool IsSavable(); + + /** + * @brief Get whether this row can be keyframed or not. + * + * @return True if this row can be keyframed. This value is set in the constructor. + */ bool IsKeyframable(); public slots: + /** + * @brief Go to previous keyframe + * + * Gets the closest keyframe prior to the current playhead and seeks to it. + * + * Attach to KeyframeNavigator::goto_previous_key() signal. + */ void GoToPreviousKeyframe(); + + /** + * @brief Toggle a keyframe at this point in time + * + * Either deletes (if any child EffectFields have any keyframes here) or creates (if none do) a keyframe on all + * EffectField children at the current time. + * + * Attach to KeyframeNavigator::toggle_key() signal. + */ void ToggleKeyframe(); + + /** + * @brief Go to next keyframe + * + * Gets the closest keyframe after the current playhead and seeks to it. + * + * Attach to KeyframeNavigator::goto_next_key() signal. + */ void GoToNextKeyframe(); + + /** + * @brief Slot for whenever this EffectRow is focused. + * + * Connect UI objects gaining focus to this slot. Automatically updates the Graph Editor to attach to this row. + */ void FocusRow(); signals: + /** + * @brief Keyframing setting changed signal + * + * Emitted whenever keyframing is enabled or disabled. + * + * @param + * + * True if keyframing was enabled, false if keyframing was disabled. + */ void KeyframingSetChanged(bool); private slots: + /** + * @brief Set keyframing enabled state + * + * A user-friendly function for enabling or disabling keyframes on this row. Preferred to SetKeyframingInternal() + * for any user-initiated change. Automatically creates an undoable action so users can undo the enabling/disabling. + * Also confirms with the user when disabling keyframing whether they wish to continue and remove all the current + * keyframes. + * + * Attach to KeyframeNavigator::keyframe_enabled_changed() signal. + */ void SetKeyframingEnabled(bool); private: + /** + * @brief Internal variable for the row's name + * + * Set in the constructor, retrieved with name(). + */ QString name_; + /** + * @brief Internal variable for whether this row can be keyframed. + * + * Set in the constructor, retrieved with IsKeyframable(). + */ bool keyframable_; + + /** + * @brief Internal variable for whether this row is currently keyframing. + * + * Set by SetKeyframingInternal() and retrieved with IsKeyframing(). + */ bool keyframing_; + + /** + * @brief Internal variable for whether this row should be saved. + * + * Set in the constructor, retrieved with IsSavable(). + */ bool savable_; + /** + * @brief Internal array of EffectField objects. + * + * It is not necessary to delete the elements in this array as they're already children of this QObject, so they'll + * get freed automatically. + */ QVector fields_; }; diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 5132fe333..5de095626 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -155,17 +155,21 @@ void EffectControls::copy(bool del) { if (open_effects_.at(i)->IsSelected()) { Effect* e = open_effects_.at(i)->GetEffect(); - if (!cleared) { - clear_clipboard(); - cleared = true; - clipboard_type = CLIPBOARD_TYPE_EFFECT; - } + if (e->meta->type == EFFECT_TYPE_EFFECT) { - clipboard.append(e->copy(nullptr)); + if (!cleared) { + clear_clipboard(); + cleared = true; + clipboard_type = CLIPBOARD_TYPE_EFFECT; + } - if (del) { + clipboard.append(e->copy(nullptr)); - DeleteEffect(ca, e); + if (del) { + + DeleteEffect(ca, e); + + } } } diff --git a/ui/effectui.cpp b/ui/effectui.cpp index 836a4836e..aca514805 100644 --- a/ui/effectui.cpp +++ b/ui/effectui.cpp @@ -10,8 +10,7 @@ #include "panels/panels.h" EffectUI::EffectUI(Effect* e) : - effect_(e), - multiple_(false) + effect_(e) { Q_ASSERT(e != nullptr); @@ -75,7 +74,7 @@ EffectUI::EffectUI(Effect* e) : connect(title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, - SIGNAL(TitleBarContextMenuRequested(const QPoint&))); + SLOT(show_context_menu(const QPoint&))); int maximum_column = 0; @@ -136,7 +135,6 @@ EffectUI::EffectUI(Effect* e) : } - keyframe_navigators_[i] = nav; } @@ -152,12 +150,10 @@ void EffectUI::AddAdditionalEffect(Effect *e) Q_ASSERT(e->meta == effect_->meta); // Add multiple modifer to header label (but only once) - if (!multiple_) { + if (additional_effects_.isEmpty()) { QString new_title = tr("%1 (multiple)").arg(Title()); SetTitle(new_title); - - multiple_ = true; } // Add effect to list diff --git a/ui/effectui.h b/ui/effectui.h index eb9be8dbf..53f04da6d 100644 --- a/ui/effectui.h +++ b/ui/effectui.h @@ -4,39 +4,195 @@ #include "collapsiblewidget.h" #include "effects/effect.h" +/** + * @brief The EffectUI class + * + * EffectUI is a complete QWidget-based representation of an Effect that can be added to any Qt layout. It overrides + * CollapsibleWidget (meaning the Effect can be collapsed to just a titlebar to save space). The titlebar is + * automatically set to the Effect's name and the contents are composed of a grid layout (QGridLayout) corresponding + * to the Effect's EffectRow and EffectField children. + * + * Many EffectUIs can be created from a single Effect, and many Effects can be attached to a single EffectUI (provided + * the Effects are all the same type). Neither gains ownership of each other and deleting an EffectUI without any other + * work is perfectly safe (deleting an Effect with an open EffectUI however, is not). + */ class EffectUI : public CollapsibleWidget { Q_OBJECT public: + /** + * @brief EffectUI Constructor + * + * Creates a QWidget-based UI representation of an Effect. + * + * @param e + * + * The Effect to make a UI of. It must be a valid object. + */ EffectUI(Effect* e); + /** + * @brief Attach additional effects to this UI + * + * Olive allows users to modify several effects (of the same type) with one UI representation. To do this, you can + * add any amount of extra Effect objects using this function and the UI will attach all of its UI functions to that + * Effect as well without creating any new QWidgets. + * + * @param e + * + * The Effect to add to this UI object. + */ void AddAdditionalEffect(Effect* e); + /** + * @brief Get the primary Effect that this UI object was created for + * + * @return + * + * The Effect object passed to the constrcutor whe creating this EffectUI. + */ Effect* GetEffect(); + /** + * @brief Get the Y position of a given row + * + * Retrieve the on-screen Y position of the attached Effect's EffectRow at a given index. This is primarily used for + * displaying UI elements that align with the the row's on-screen widgets (e.g. keyframes in the EffectControls + * panel). + * + * The Y value provided is specifically the center point of the row's name label. It gets mapped to a provided + * QWidget object so it can be used locally by that QWidget without further modification. + * + * @param row + * + * The index of the EffectRow to retrieve the Y position of. + * + * @param mapToWidget + * + * The widget to map the Y value to. + * + * @return + * + * The row's Y position. + */ int GetRowY(int row, QWidget *mapToWidget); + /** + * @brief Update widgets with the current Effect's values. + * + * When the Timeline playhead moves, the current values in the Effect might change if its fields are keyframed. + * In order to visually update these values on the UI, this function should be called. It will loop through all + * fields of all attached effects and update them to the value at the current Timeline playhead. + * + * Currently this function is called by update_ui() which is also responsible for updating other parts of the UI + * like the Timeline and Viewer so they all get updated together. + */ void UpdateFromEffect(); + /** + * @brief Check if a given Clip has an Effect referenced by this EffectUI + * + * Olive allows users to modify several effects (of the same type) with one UI representation. The behavior is if + * multiple clips are selected that have effects of the same type, all those Effects can be modified by the same + * EffectUI object. However this behavior is undesirable if a single Clip has more than one of the same type of Effect + * (e.g. two or more blurs). In this scenario, the user will most likely expect two separate UI objects for each of + * these effects individually, rather than consolidating them into one UI object. + * + * To address this, EffectControls will check this function to determine if this EffectUI already references + * an Effect of this type from this Clip. If it does, it's assumed a new EffectUI should be made rather than + * consolidating that Effect into the same EffectUI. + * + * @param c + * + * The Clip to determine whether an Effect of this type is already referenced by this EffectUI. + * + * @return + * + * True is an Effect from this Clip is already attached to this EffectUI. + */ bool IsAttachedToClip(Clip* c); signals: + /** + * @brief Cut signal + * + * Emitted when the user selects Cut from the right-click context menu. + */ void CutRequested(); + + /** + * @brief Copy signal + * + * Emitted when the user selects Copy from the right-click context menu. + */ void CopyRequested(); - void TitleBarContextMenuRequested(const QPoint&); private: + /** + * @brief Retrieve the QWidget corresponding a specific EffectField + * + * Convenience function equivalent to widgets_.at(row).at(field). + * + * @param row + * + * EffectRow index to retrieve field QWidget from + * + * @param field + * + * EffectField index to retrieve QWidget from + * + * @return + * + * The QWidget at this row and field index. + */ QWidget* Widget(int row, int field); + /** + * @brief Internal reference to the Effect this object was constructed around. + */ Effect* effect_; + + /** + * @brief Internal array of additional Effect objects attached to this UI. + */ QVector additional_effects_; + + /** + * @brief Layout for UI widgets + */ QGridLayout* layout_; - QVector labels_; + + /** + * @brief Grid array of QWidgets corresponding to the Effect's rows and fields + */ QVector< QVector > widgets_; + + /** + * @brief Array of QLabel objects corresponding to each row's name(). + */ + QVector labels_; + + /** + * @brief Array of KeyframeNavigator objects corresponding to each row. + */ QVector keyframe_navigators_; - bool multiple_; - + /** + * @brief Attach a KeyframeNavigator object to an EffectRow. + * + * Internal function for connecting a KeyframeNavigator UI object to an EffectRow. + * + * @param row + * + * The EffectRow object. + * + * @param nav + * + * The KeyframeNavigator object. + */ void AttachKeyframeNavigationToRow(EffectRow* row, KeyframeNavigator* nav); private slots: + /** + * @brief Slot for titlebar's right-click signal to show a context menu for extra Effect functions. + */ void show_context_menu(const QPoint&); }; From 1d11e3102923a0c34299884a4fad786c65e66668 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 16 Mar 2019 17:56:01 +1100 Subject: [PATCH 56/56] added more documentation --- effects/effectloaders.cpp | 2 +- effects/effectloaders.h | 18 ++++++++-- panels/panels.cpp | 3 +- ui/audiomonitor.h | 69 ++++++++++++++++++++++++++++++++++----- ui/blur.h | 19 +++++++++++ 5 files changed, 97 insertions(+), 14 deletions(-) diff --git a/effects/effectloaders.cpp b/effects/effectloaders.cpp index d53390ab5..d6bf208c1 100644 --- a/effects/effectloaders.cpp +++ b/effects/effectloaders.cpp @@ -187,7 +187,7 @@ void load_shader_effects() { } } -void init_effects() { +void EffectInit::StartLoading() { EffectInit* init_thread = new EffectInit(); QObject::connect(init_thread, SIGNAL(finished()), init_thread, SLOT(deleteLater())); init_thread->start(); diff --git a/effects/effectloaders.h b/effects/effectloaders.h index a5370df41..e4a3da21e 100644 --- a/effects/effectloaders.h +++ b/effects/effectloaders.h @@ -24,12 +24,26 @@ #include #include -void init_effects(); - +/** + * @brief The EffectInit class + * + * A separate thread for loading effects in the background while the rest of the program's initiation takes place. + * The program can even run before the effects have finished loading, but any point the software needs to access + * effects, it will have to wait for this thread to finish before it can. Fortunately this thread is usually very + * quick and is over before the MainWindow shows. + */ class EffectInit : public QThread { public: EffectInit(); + + /** + * @brief A static convenience function to set up the EffectInit thread, start it, and free itself when complete. + */ + static void StartLoading(); protected: + /** + * @brief Function that runs in the other thread. + */ void run(); }; diff --git a/panels/panels.cpp b/panels/panels.cpp index 0f01dee03..30af5c7f2 100644 --- a/panels/panels.cpp +++ b/panels/panels.cpp @@ -83,7 +83,6 @@ QDockWidget *get_focused_panel(bool force_hover) { } 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); @@ -91,7 +90,7 @@ void alloc_panels(QWidget* parent) { panel_project = new Project(parent); panel_project->setObjectName("proj_root"); panel_effect_controls = new EffectControls(parent); - init_effects(); + EffectInit::StartLoading(); panel_effect_controls->setObjectName("fx_controls"); panel_timeline = new Timeline(parent); panel_timeline->setObjectName("timeline"); diff --git a/ui/audiomonitor.h b/ui/audiomonitor.h index b2e72c1d6..39a40d39a 100644 --- a/ui/audiomonitor.h +++ b/ui/audiomonitor.h @@ -24,28 +24,79 @@ #include #include +/** + * @brief The AudioMonitor class + * + * Used to show a visual representation of audio currently playing + */ class AudioMonitor : public QWidget { - Q_OBJECT + Q_OBJECT public: - explicit AudioMonitor(QWidget *parent = 0); - void set_value(const QVector& values); + /** + * @brief AudioMonitor Constructor + * @param parent + * + * QWidget parent object. + */ + explicit AudioMonitor(QWidget *parent = nullptr); + + /** + * @brief Set the current audio value + * + * The main interface for updating the audio monitor. Using this function will redraw the monitor with the values + * specified. + * + * @param values + * + * An array of doubles between 0.0 and 1.0 to display the amplitude. 0.0 is no audio, 1.0 is full volume. Each array + * entry is a channel and the audio monitor will automatically adjust to the channel count in the array. + */ + void set_value(const QVector& values); protected: - void paintEvent(QPaintEvent *); - void resizeEvent(QResizeEvent *); + /** + * @brief Internal paint event + * + * Paints the + */ + void paintEvent(QPaintEvent *); + + /** + * @brief Internal resize event handler + * + * Triggers a repaint when the widget is resized. + */ + void resizeEvent(QResizeEvent *); signals: public slots: private: - QLinearGradient gradient; - QVector values; - QTimer clear_timer; + /** + * @brief Internal gradient object from red to yellow to green + */ + QLinearGradient gradient; + + /** + * @brief Internal value storage + */ + QVector values; + + /** + * @brief Internal timer to clear the audio monitor after a certain amount of time + * + * If it doesn't receive any values within a certain amount of time, it's assumed audio is no longer playing and the + * monitor is cleared. + */ + QTimer clear_timer; private slots: - void clear(); + /** + * @brief Slot to clear the audio monitor + */ + void clear(); }; #endif // AUDIOMONITOR_H diff --git a/ui/blur.h b/ui/blur.h index ddf44fb86..6e56ea032 100644 --- a/ui/blur.h +++ b/ui/blur.h @@ -6,6 +6,25 @@ namespace olive { namespace ui { + /** + * @brief Convenience function for blurring a QImage + * + * @param result + * + * QImage to blur + * + * @param rect + * + * The rectangle of the QImage to blur. Use QImage::rect() to blur the entire image. + * + * @param radius + * + * The blur radius - how much to blur the image. + * + * @param alphaOnly + * + * True if only the alpha channel should be blurred rather than the entire RGBA space. + */ void blur(QImage& result, const QRect& rect, int radius, bool alphaOnly); } }