decoupled effectfield UI from backend
This commit is contained in:
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "colorfield.h"
|
||||
|
||||
#include <QColor>
|
||||
|
||||
ColorField::ColorField(EffectRow* parent, const QString& id) :
|
||||
EffectField(parent, id, EFFECT_FIELD_COLOR)
|
||||
{}
|
||||
|
||||
QColor ColorField::GetColorAt(double timecode)
|
||||
{
|
||||
return GetValueAt(timecode).value<QColor>();
|
||||
}
|
||||
|
||||
QVariant ColorField::ConvertStringToValue(const QString &s)
|
||||
{
|
||||
return QColor(s);
|
||||
}
|
||||
|
||||
QString ColorField::ConvertValueToString(const QVariant &v)
|
||||
{
|
||||
return v.value<QColor>().name();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef COMBOFIELD_H
|
||||
#define COMBOFIELD_H
|
||||
|
||||
#include "effectfield.h"
|
||||
|
||||
struct ComboFieldItem {
|
||||
QString name;
|
||||
QVector<QVariant> 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<ComboFieldItem> items_;
|
||||
};
|
||||
|
||||
#endif // COMBOFIELD_H
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#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 <QDateTime>
|
||||
#include <QtMath>
|
||||
|
||||
#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<EffectRow*>(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<QColor>();
|
||||
} else {
|
||||
QColor before_data = keyframes.at(before_keyframe).data.value<QColor>();
|
||||
QColor after_data = keyframes.at(after_keyframe).data.value<QColor>();
|
||||
value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress));
|
||||
}
|
||||
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.size();i++) {
|
||||
if (i != key
|
||||
&& ((keyframes.at(i).time > 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<keyframes.size();i++) {
|
||||
long eval_keyframe_time = keyframes.at(i).time;
|
||||
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 (GetParentRow()->isKeyframing() && keyframes.size() > 1);
|
||||
}
|
||||
|
||||
void EffectField::ui_element_change() {
|
||||
// TODO address this
|
||||
//bool dragging_double = (type_ == EFFECT_FIELD_DOUBLE && static_cast<LabelSlider*>(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_);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef EFFECTFIELD_H
|
||||
#define EFFECTFIELD_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#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<EffectKeyframe> 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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user