From c168bf1a80e6322f7d28ab122d4bb9fa292bfe23 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 7 Mar 2020 01:21:36 +1100 Subject: [PATCH] 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. --- app/node/audio/pan/pan.cpp | 5 +- app/node/audio/volume/volume.cpp | 5 +- app/node/distort/transform/transform.cpp | 6 +- app/node/input.cpp | 52 +++------ app/node/input.h | 53 +++++---- app/node/metareader.cpp | 21 +--- .../nodeparamviewwidgetbridge.cpp | 107 +++++++++--------- .../nodeparamview/nodeparamviewwidgetbridge.h | 2 + 8 files changed, 118 insertions(+), 133 deletions(-) diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index dcc61f963..4342c63a9 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -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_); } diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 5afda4786..9b1dbed6f 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -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_); } diff --git a/app/node/distort/transform/transform.cpp b/app/node/distort/transform/transform.cpp index 7e0e309c9..8660a38b8 100644 --- a/app/node/distort/transform/transform.cpp +++ b/app/node/distort/transform/transform.cpp @@ -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()*0.01f; + QVector2D scale = value[scale_input_].Get(NodeParam::kVec2).value(); if (value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool()) { scale.setY(scale.x()); } diff --git a/app/node/input.cpp b/app/node/input.cpp index 77d5c63b9..db7f39150 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -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 NodeInput::split_normal_value_into_track_values(const QVariant &value) const { QVector vals(get_number_of_keyframe_tracks()); diff --git a/app/node/input.h b/app/node/input.h index 6957c7bfc..8b5fd3fbc 100644 --- a/app/node/input.h +++ b/app/node/input.h @@ -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 split_normal_value_into_track_values(const QVariant &value) const; QVariant combine_track_values_into_normal_value(const QVector& 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& param_ptrs, QList &input_connections, QList& 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 properties_; private slots: /** diff --git a/app/node/metareader.cpp b/app/node/metareader.cpp index aeba47dbb..dd4c9f7a4 100644 --- a/app/node/metareader.cpp +++ b/app/node/metareader.cpp @@ -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 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::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) { diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 444140f1e..16956262d 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -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()); + } + + if (input_->has_property(QStringLiteral("max"))) { + slider->SetMinimum(input_->get_property(QStringLiteral("max")).value()); + } break; } case NodeParam::kFloat: { - FloatSlider* slider = new FloatSlider(); + float min_flt = input_->get_property(QStringLiteral("min")).value(); + float max_flt = input_->get_property(QStringLiteral("max")).value(); - 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 max_vec = input_->get_property(QStringLiteral("max")).value(); - 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(&min_vec) : nullptr, + input_->has_property(QStringLiteral("max")) ? reinterpret_cast(&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 max_vec = input_->get_property(QStringLiteral("max")).value(); - 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(&min_vec) : nullptr, + input_->has_property(QStringLiteral("max")) ? reinterpret_cast(&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 max_vec = input_->get_property(QStringLiteral("max")).value(); - 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(&min_vec) : nullptr, + input_->has_property(QStringLiteral("max")) ? reinterpret_cast(&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;iSetMinimum(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_) { diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index 40c9346f9..d40c487ab 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -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 widgets_;