nodeparam: implemented parameters that allow arbitrary properties to be set
for UI representations Allows properties to be set without adding explicit extra members to NodeInputs. Crucially this means parameters like slider value representations (percent, decibel, etc.) can be set from NodeInputs now.
This commit is contained in:
@@ -6,8 +6,9 @@ PanNode::PanNode()
|
||||
AddInput(samples_input_);
|
||||
|
||||
panning_input_ = new NodeInput("panning_in", NodeParam::kFloat);
|
||||
panning_input_->set_minimum(-1);
|
||||
panning_input_->set_maximum(1);
|
||||
panning_input_->set_property("min", -1.0);
|
||||
panning_input_->set_property("max", 1.0);
|
||||
panning_input_->set_property("view", "percent");
|
||||
AddInput(panning_input_);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ VolumeNode::VolumeNode()
|
||||
AddInput(samples_input_);
|
||||
|
||||
volume_input_ = new NodeInput("volume_in", NodeParam::kFloat, 1);
|
||||
volume_input_->set_minimum(0);
|
||||
volume_input_->set_maximum(1);
|
||||
volume_input_->set_property("min", 0.0);
|
||||
volume_input_->set_property("max", 1.0);
|
||||
volume_input_->set_property("view", "db");
|
||||
AddInput(volume_input_);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ TransformDistort::TransformDistort()
|
||||
rotation_input_ = new NodeInput("rot_in", NodeParam::kFloat);
|
||||
AddInput(rotation_input_);
|
||||
|
||||
scale_input_ = new NodeInput("scale_in", NodeParam::kVec2, QVector2D(100.0f, 100.0f));
|
||||
scale_input_ = new NodeInput("scale_in", NodeParam::kVec2, QVector2D(1.0f, 1.0f));
|
||||
scale_input_->set_property("min", QVector2D(0, 0));
|
||||
scale_input_->set_property("view", "percent");
|
||||
AddInput(scale_input_);
|
||||
|
||||
uniform_scale_input_ = new NodeInput("uniform_scale_in", NodeParam::kBoolean, true);
|
||||
@@ -89,7 +91,7 @@ NodeValueTable TransformDistort::Value(const NodeValueDatabase &value) const
|
||||
mat.rotate(value[rotation_input_].Get(NodeParam::kFloat).toFloat(), 0, 0, 1);
|
||||
|
||||
// Scale and Uniform Scale
|
||||
QVector2D scale = value[scale_input_].Get(NodeParam::kVec2).value<QVector2D>()*0.01f;
|
||||
QVector2D scale = value[scale_input_].Get(NodeParam::kVec2).value<QVector2D>();
|
||||
if (value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool()) {
|
||||
scale.setY(scale.x());
|
||||
}
|
||||
|
||||
+17
-35
@@ -36,9 +36,7 @@ NodeInput::NodeInput(const QString& id, const DataType &type, const QVariant &de
|
||||
NodeParam(id),
|
||||
data_type_(type),
|
||||
keyframable_(true),
|
||||
keyframing_(false),
|
||||
has_minimum_(false),
|
||||
has_maximum_(false)
|
||||
keyframing_(false)
|
||||
{
|
||||
int track_size;
|
||||
|
||||
@@ -865,38 +863,6 @@ void NodeInput::set_is_keyframable(bool k)
|
||||
keyframable_ = k;
|
||||
}
|
||||
|
||||
const QVariant &NodeInput::minimum() const
|
||||
{
|
||||
return minimum_;
|
||||
}
|
||||
|
||||
bool NodeInput::has_minimum() const
|
||||
{
|
||||
return has_minimum_;
|
||||
}
|
||||
|
||||
void NodeInput::set_minimum(const QVariant &min)
|
||||
{
|
||||
minimum_ = min;
|
||||
has_minimum_ = true;
|
||||
}
|
||||
|
||||
const QVariant &NodeInput::maximum() const
|
||||
{
|
||||
return maximum_;
|
||||
}
|
||||
|
||||
bool NodeInput::has_maximum() const
|
||||
{
|
||||
return has_maximum_;
|
||||
}
|
||||
|
||||
void NodeInput::set_maximum(const QVariant &max)
|
||||
{
|
||||
maximum_ = max;
|
||||
has_maximum_ = true;
|
||||
}
|
||||
|
||||
void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections)
|
||||
{
|
||||
Q_ASSERT(source->id() == dest->id());
|
||||
@@ -935,6 +901,22 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
|
||||
emit dest->ValueChanged(RATIONAL_MIN, RATIONAL_MAX);
|
||||
}
|
||||
|
||||
void NodeInput::set_property(const QString &key, const QVariant &value)
|
||||
{
|
||||
properties_.insert(key, value);
|
||||
emit PropertyChanged(key, value);
|
||||
}
|
||||
|
||||
QVariant NodeInput::get_property(const QString &key) const
|
||||
{
|
||||
return properties_.value(key);
|
||||
}
|
||||
|
||||
bool NodeInput::has_property(const QString &key) const
|
||||
{
|
||||
return properties_.contains(key);
|
||||
}
|
||||
|
||||
QVector<QVariant> NodeInput::split_normal_value_into_track_values(const QVariant &value) const
|
||||
{
|
||||
QVector<QVariant> vals(get_number_of_keyframe_tracks());
|
||||
|
||||
+28
-25
@@ -216,19 +216,35 @@ public:
|
||||
*/
|
||||
void set_is_keyframable(bool k);
|
||||
|
||||
const QVariant& minimum() const;
|
||||
bool has_minimum() const;
|
||||
void set_minimum(const QVariant& min);
|
||||
|
||||
const QVariant& maximum() const;
|
||||
bool has_maximum() const;
|
||||
void set_maximum(const QVariant& max);
|
||||
|
||||
/**
|
||||
* @brief Copy all values including keyframe information and connections from another NodeInput
|
||||
*/
|
||||
static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true);
|
||||
|
||||
/**
|
||||
* @brief Set an arbitrary property on this input to influence a UI representation's behavior
|
||||
*
|
||||
* NodeInputs also utilize QObject's property key/value system for arbitrary properties that can influence the UI
|
||||
* representation's behavior.
|
||||
*
|
||||
* Currently supported properties:
|
||||
*
|
||||
* - `min` - For any numeral type represented with a slider, prevents values going BELOW this number
|
||||
* - `max` - For any numeral type represented with a slider, prevents values going ABOVE this number
|
||||
* - `view` - For any numeral type represented with a slider, shows number either as `db`, `percent`, or `normal`
|
||||
*/
|
||||
void set_property(const QString& key, const QVariant& value);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a property (or an empty QVariant if it hasn't been set)
|
||||
*/
|
||||
QVariant get_property(const QString& key) const;
|
||||
|
||||
/**
|
||||
* @brief Return whether a certain property has been set or not
|
||||
*/
|
||||
bool has_property(const QString& key) const;
|
||||
|
||||
QVector<QVariant> split_normal_value_into_track_values(const QVariant &value) const;
|
||||
|
||||
QVariant combine_track_values_into_normal_value(const QVector<QVariant>& split) const;
|
||||
@@ -242,6 +258,8 @@ signals:
|
||||
|
||||
void KeyframeRemoved(NodeKeyframePtr key);
|
||||
|
||||
void PropertyChanged(const QString& s, const QVariant& v);
|
||||
|
||||
protected:
|
||||
virtual void LoadInternal(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections, const QAtomicInt* cancelled);
|
||||
|
||||
@@ -325,24 +343,9 @@ private:
|
||||
bool keyframing_;
|
||||
|
||||
/**
|
||||
* @brief Sets whether this param has a minimum value or not
|
||||
* @brief Internal properties variable
|
||||
*/
|
||||
bool has_minimum_;
|
||||
|
||||
/**
|
||||
* @brief Internal minimum value
|
||||
*/
|
||||
QVariant minimum_;
|
||||
|
||||
/**
|
||||
* @brief Sets whether this param has a maximum value or not
|
||||
*/
|
||||
bool has_maximum_;
|
||||
|
||||
/**
|
||||
* @brief Internal maximum value
|
||||
*/
|
||||
QVariant maximum_;
|
||||
QHash<QString, QVariant> properties_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
|
||||
+6
-15
@@ -194,10 +194,7 @@ void NodeMetaReader::XMLReadParam(QXmlStreamReader *reader)
|
||||
}
|
||||
|
||||
QVariant default_val;
|
||||
QVariant min_val;
|
||||
bool has_min = false;
|
||||
QVariant max_val;
|
||||
bool has_max = false;
|
||||
QHash<QString, QVariant> properties;
|
||||
|
||||
// Traverse through param contents for more data
|
||||
while (!reader->atEnd() && !(reader->isEndElement() && reader->name() == "param")) {
|
||||
@@ -218,24 +215,18 @@ void NodeMetaReader::XMLReadParam(QXmlStreamReader *reader)
|
||||
|
||||
} else if (reader->name() == "default") {
|
||||
default_val = reader->readElementText();
|
||||
} else if (reader->name() == "min") {
|
||||
has_min = true;
|
||||
min_val = reader->readElementText();
|
||||
} else if (reader->name() == "max") {
|
||||
has_max = true;
|
||||
max_val = reader->readElementText();
|
||||
} else {
|
||||
properties.insert(reader->name().toString(), reader->readElementText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeInput* input = new NodeInput(param_id, param_type, default_val);
|
||||
|
||||
if (has_min) {
|
||||
input->set_minimum(min_val);
|
||||
}
|
||||
QHash<QString, QVariant>::const_iterator iterator;
|
||||
|
||||
if (has_max) {
|
||||
input->set_maximum(max_val);
|
||||
for (iterator=properties.begin();iterator!=properties.end();iterator++) {
|
||||
input->set_property(iterator.key(), iterator.value());
|
||||
}
|
||||
|
||||
if (is_iterative) {
|
||||
|
||||
@@ -135,80 +135,60 @@ void NodeParamViewWidgetBridge::CreateWidgets()
|
||||
case NodeParam::kInt:
|
||||
{
|
||||
IntegerSlider* slider = new IntegerSlider();
|
||||
|
||||
if (input_->has_minimum()) {
|
||||
slider->SetMinimum(input_->minimum().toLongLong());
|
||||
}
|
||||
|
||||
if (input_->has_maximum()) {
|
||||
slider->SetMaximum(input_->maximum().toLongLong());
|
||||
}
|
||||
|
||||
widgets_.append(slider);
|
||||
connect(slider, &IntegerSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
|
||||
widgets_.append(slider);
|
||||
if (input_->has_property(QStringLiteral("min"))) {
|
||||
slider->SetMinimum(input_->get_property(QStringLiteral("min")).value<int64_t>());
|
||||
}
|
||||
|
||||
if (input_->has_property(QStringLiteral("max"))) {
|
||||
slider->SetMinimum(input_->get_property(QStringLiteral("max")).value<int64_t>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFloat:
|
||||
{
|
||||
FloatSlider* slider = new FloatSlider();
|
||||
float min_flt = input_->get_property(QStringLiteral("min")).value<float>();
|
||||
float max_flt = input_->get_property(QStringLiteral("max")).value<float>();
|
||||
|
||||
if (input_->has_minimum()) {
|
||||
slider->SetMinimum(input_->minimum().toDouble());
|
||||
}
|
||||
|
||||
if (input_->has_maximum()) {
|
||||
slider->SetMaximum(input_->maximum().toDouble());
|
||||
}
|
||||
|
||||
connect(slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
|
||||
widgets_.append(slider);
|
||||
CreateSliders(1,
|
||||
input_->has_property(QStringLiteral("min")) ? &min_flt : nullptr,
|
||||
input_->has_property(QStringLiteral("max")) ? &max_flt : nullptr,
|
||||
input_->get_property(QStringLiteral("view")).toString());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec2:
|
||||
{
|
||||
FloatSlider* x_slider = new FloatSlider();
|
||||
widgets_.append(x_slider);
|
||||
connect(x_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
QVector2D min_vec = input_->get_property(QStringLiteral("min")).value<QVector2D>();
|
||||
QVector2D max_vec = input_->get_property(QStringLiteral("max")).value<QVector2D>();
|
||||
|
||||
FloatSlider* y_slider = new FloatSlider();
|
||||
widgets_.append(y_slider);
|
||||
connect(y_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
CreateSliders(2,
|
||||
input_->has_property(QStringLiteral("min")) ? reinterpret_cast<float*>(&min_vec) : nullptr,
|
||||
input_->has_property(QStringLiteral("max")) ? reinterpret_cast<float*>(&max_vec) : nullptr,
|
||||
input_->get_property(QStringLiteral("view")).toString());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec3:
|
||||
{
|
||||
FloatSlider* x_slider = new FloatSlider();
|
||||
widgets_.append(x_slider);
|
||||
connect(x_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
QVector3D min_vec = input_->get_property(QStringLiteral("min")).value<QVector3D>();
|
||||
QVector3D max_vec = input_->get_property(QStringLiteral("max")).value<QVector3D>();
|
||||
|
||||
FloatSlider* y_slider = new FloatSlider();
|
||||
widgets_.append(y_slider);
|
||||
connect(y_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
|
||||
FloatSlider* z_slider = new FloatSlider();
|
||||
widgets_.append(z_slider);
|
||||
connect(z_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
CreateSliders(3,
|
||||
input_->has_property(QStringLiteral("min")) ? reinterpret_cast<float*>(&min_vec) : nullptr,
|
||||
input_->has_property(QStringLiteral("max")) ? reinterpret_cast<float*>(&max_vec) : nullptr,
|
||||
input_->get_property(QStringLiteral("view")).toString());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kVec4:
|
||||
{
|
||||
FloatSlider* x_slider = new FloatSlider();
|
||||
widgets_.append(x_slider);
|
||||
connect(x_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
QVector4D min_vec = input_->get_property(QStringLiteral("min")).value<QVector4D>();
|
||||
QVector4D max_vec = input_->get_property(QStringLiteral("max")).value<QVector4D>();
|
||||
|
||||
FloatSlider* y_slider = new FloatSlider();
|
||||
widgets_.append(y_slider);
|
||||
connect(y_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
|
||||
FloatSlider* z_slider = new FloatSlider();
|
||||
widgets_.append(z_slider);
|
||||
connect(z_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
|
||||
FloatSlider* w_slider = new FloatSlider();
|
||||
widgets_.append(w_slider);
|
||||
connect(w_slider, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
CreateSliders(4,
|
||||
input_->has_property(QStringLiteral("min")) ? reinterpret_cast<float*>(&min_vec) : nullptr,
|
||||
input_->has_property(QStringLiteral("max")) ? reinterpret_cast<float*>(&max_vec) : nullptr,
|
||||
input_->get_property(QStringLiteral("view")).toString());
|
||||
break;
|
||||
}
|
||||
case NodeParam::kFile:
|
||||
@@ -444,6 +424,29 @@ void NodeParamViewWidgetBridge::WidgetCallback()
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::CreateSliders(int count, float *min, float *max, const QString &type)
|
||||
{
|
||||
for (int i=0;i<count;i++) {
|
||||
FloatSlider* fs = new FloatSlider();
|
||||
widgets_.append(fs);
|
||||
connect(fs, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
|
||||
|
||||
if (min) {
|
||||
fs->SetMinimum(min[i]);
|
||||
}
|
||||
|
||||
if (max) {
|
||||
fs->SetMaximum(max[i]);
|
||||
}
|
||||
|
||||
if (type == QStringLiteral("percent")) {
|
||||
fs->SetDisplayType(FloatSlider::kPercentage);
|
||||
} else if (type == QStringLiteral("db")) {
|
||||
fs->SetDisplayType(FloatSlider::kDecibel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewWidgetBridge::InputValueChanged(const rational &start, const rational &end)
|
||||
{
|
||||
if (!dragging_ && start <= time_ && end >= time_) {
|
||||
|
||||
@@ -23,6 +23,8 @@ private:
|
||||
|
||||
void ProcessSlider(SliderBase* slider, const QVariant& value);
|
||||
|
||||
void CreateSliders(int count, float *min, float *max, const QString& type);
|
||||
|
||||
NodeInput* input_;
|
||||
|
||||
QList<QWidget*> widgets_;
|
||||
|
||||
Reference in New Issue
Block a user