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_;