#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 "effectrow.h" #include "effect.h" #include "project/undo.h" #include "project/clip.h" #include "project/sequence.h" #include "io/math.h" #include 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())); } 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(); 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; } } 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(); } 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(); } 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()); } } 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;ikeyframe_times.size();i++) { long eval_keyframe_time = parent_row->keyframe_times.at(i); if (eval_keyframe_time == frame) { before = i; after = i; return; } else if (eval_keyframe_time < frame && eval_keyframe_time > 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() && keyframe_data.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); int kf_type = (progress < 0.5) ? parent_row->keyframe_types.at(before_keyframe) : parent_row->keyframe_types.at(after_keyframe); if (kf_type == KEYFRAME_TYPE_SMOOTH) { double x = (8.0 * progress) - 4.0; progress = 1.0 / (1.0 + qPow(M_E, -x)); progress *= 1.0373; progress -= 0.01865; } const QVariant& before_data = keyframe_data.at(before_keyframe); switch (type) { case EFFECT_FIELD_DOUBLE: { double value; if (before_keyframe == after_keyframe) { value = keyframe_data.at(before_keyframe).toDouble(); } else { double before_dbl = keyframe_data.at(before_keyframe).toDouble(); double after_dbl = keyframe_data.at(after_keyframe).toDouble(); 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 = keyframe_data.at(before_keyframe).value(); } else { QColor before_data = keyframe_data.at(before_keyframe).value(); QColor after_data = keyframe_data.at(after_keyframe).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; } } return QVariant(); } void EffectField::ui_element_change() { bool dragging_double = (type == EFFECT_FIELD_DOUBLE && static_cast(ui_element)->is_dragging()); ComboAction* ca = NULL; if (!dragging_double) ca = new ComboAction(); make_key_from_change(ca); if (!dragging_double) undo_stack.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 != NULL) { // set undo ca->append(new EffectFieldUndo(this)); } } QWidget* EffectField::get_ui_element() { return ui_element; } 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(); } const QVariant EffectField::get_combo_data(double timecode) { validate_keyframe_data(timecode); return static_cast(ui_element)->currentData(); } const 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); } const 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); } const 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); }