diff --git a/addons/ofxGui/src/ofxSlider.cpp b/addons/ofxGui/src/ofxSlider.cpp index e9f95d55790..0506863d52b 100644 --- a/addons/ofxGui/src/ofxSlider.cpp +++ b/addons/ofxGui/src/ofxSlider.cpp @@ -219,7 +219,7 @@ void ofxSlider::generateDraw(){ bg.setFillColor(thisBackgroundColor); bg.setExtents(b); - float valAsPct = ofMap( value, value.getMin(), value.getMax(), 0, b.width-2, true ); + float valAsPct = ofClamp(value.getPctScaled(),0,1); bar.setFillColor(thisFillColor); bar.setExtents(b.x+1, b.y+1, valAsPct, b.height-2); @@ -314,7 +314,7 @@ bool ofxSlider::setValue(float mx, float my, bool bCheck){ } } if( bGuiActive ){ - value = ofMap(mx, b.x, b.x + b.width, value.getMin(), value.getMax(), true); + value.setPctScaled(ofMap(mx, b.x, b.x + b.width, 0, 1, true)); return true; } return false; diff --git a/libs/openFrameworks/types/ofParameter.h b/libs/openFrameworks/types/ofParameter.h index 6dcd27435a8..4579f1706ec 100644 --- a/libs/openFrameworks/types/ofParameter.h +++ b/libs/openFrameworks/types/ofParameter.h @@ -485,6 +485,11 @@ typename std::enable_if::value, Pa } /*! \endcond */ +enum class ofParameterScale{ + Linear, + Logarithmic, +}; + /// \brief ofParameter holds a value and notifies its listeners when it changes. /// /// ofParameter can be used as the value itself. For example an `ofParameter` @@ -501,8 +506,9 @@ class ofParameter : public ofAbstractParameter { ofParameter(); ofParameter(const ofParameter & v); ofParameter(const ParameterType & v); - ofParameter(const std::string & name, const ParameterType & v); - ofParameter(const std::string & name, const ParameterType & v, const ParameterType & min, const ParameterType & max); + ofParameter(const std::string& name, const ParameterType & v); + ofParameter(const std::string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max); + ofParameter(const std::string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max, ofParameterScale scale); const ParameterType & get() const; const ParameterType * operator->() const; @@ -543,6 +549,11 @@ class ofParameter : public ofAbstractParameter { return obj->changedE.newListener(args...); } + template + void ownListener(Args...args) { + obj->ownListeners.push_back(obj->changedE.newListener(args...)); + } + void enableEvents(); void disableEvents(); bool isSerializable() const; @@ -592,6 +603,15 @@ class ofParameter : public ofAbstractParameter { void setInit(const ParameterType & init); bool isInit() const; + template + typename std::enable_if::value, void>::type setScale(ofParameterScale scale); + template + typename std::enable_if::value, ofParameterScale>::type getScale() const; + template + typename std::enable_if::value, void>::type setPctScaled(double value); + template + typename std::enable_if::value, double>::type getPctScaled() const; + void setSerializable(bool serializable); std::shared_ptr newReference() const; @@ -613,7 +633,38 @@ class ofParameter : public ofAbstractParameter { protected: private: - class Value { + template + class Scale; + + template + class Scale::value, T>::type>{ + public: + ofParameterScale scale; + Scale():scale(ofParameterScale::Linear){} + Scale(ofParameterScale scale):scale(scale){} + Scale & operator=(ofParameterScale scale){ + this->scale = scale; + return *this; + } + operator ofParameterScale(){ + return scale; + } + }; + + template + class Scale::value, T>::type>{ + public: + Scale(){} + Scale(ofParameterScale){} + Scale & operator=(ofParameterScale){ + return *this; + } + operator ofParameterScale(){ + return ofParameterScale::Linear; + } + }; + + class Value{ public: Value() : init(of::priv::TypeInfo::min()) @@ -623,37 +674,50 @@ class ofParameter : public ofAbstractParameter { , serializable(true) { } Value(ParameterType v) - : init(v) - , value(v) - , min(of::priv::TypeInfo::min()) - , max(of::priv::TypeInfo::max()) - , bInNotify(false) - , serializable(true) { } - - Value(std::string name, ParameterType v) - : name(name) - , init(v) - , value(v) - , min(of::priv::TypeInfo::min()) - , max(of::priv::TypeInfo::max()) - , bInNotify(false) - , serializable(true) { } - - Value(std::string name, ParameterType v, ParameterType min, ParameterType max) - : name(name) - , init(v) - , value(v) - , min(min) - , max(max) - , bInNotify(false) - , serializable(true) { } + :value(v) + ,init(v) + ,min(of::priv::TypeInfo::min()) + ,max(of::priv::TypeInfo::max()) + ,bInNotify(false) + ,serializable(true){} + + Value(string name, ParameterType v) + :name(name) + ,init(v) + ,value(v) + ,min(of::priv::TypeInfo::min()) + ,max(of::priv::TypeInfo::max()) + ,bInNotify(false) + ,serializable(true){} + + Value(string name, ParameterType v, ParameterType min, ParameterType max) + :name(name) + ,init(v) + ,value(v) + ,min(min) + ,max(max) + ,bInNotify(false) + ,serializable(true){} + + Value(string name, ParameterType v, ParameterType min, ParameterType max, ofParameterScale scale) + :name(name) + ,init(v) + ,value(v) + ,min(min) + ,max(max) + ,bInNotify(false) + ,serializable(true) + ,scale(scale){} std::string name; - ParameterType init, value, min, max; + ParameterType value; + ParameterType min, max; ofEvent changedE; bool bInNotify; bool serializable; - std::vector> parents; + std::vector> parents; + std::vector ownListeners; + Scale scale; }; std::shared_ptr obj; @@ -691,8 +755,13 @@ ofParameter::ofParameter(const std::string & name, const Paramete : obj(std::make_shared(name, v, min, max)) , setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)) { } -template -inline ofParameter & ofParameter::operator=(const ofParameter & v) { +template +ofParameter::ofParameter(const string& name, const ParameterType & v, const ParameterType & min, const ParameterType & max, ofParameterScale scale) +:obj(std::make_shared(name, v, min, max, scale)) +,setMethod(std::bind(&ofParameter::eventsSetValue, this, std::placeholders::_1)){} + +template +inline ofParameter & ofParameter::operator=(const ofParameter & v){ set(v); return *this; } @@ -889,8 +958,59 @@ void ofParameter::disableEvents() { setMethod = std::bind(&ofParameter::noEventsSetValue, this, std::placeholders::_1); } -template -inline ParameterType ofParameter::operator++(int) { + +template +template +typename std::enable_if::value, void>::type ofParameter::setScale(ofParameterScale scale){ + obj->scale = scale; +} + +template +template +typename std::enable_if::value, ofParameterScale>::type ofParameter::getScale() const{ + return obj->scale; +} + +template +template +typename std::enable_if::value, void>::type ofParameter::setPctScaled(double pct){ + switch(static_cast(obj->scale)){ + case ofParameterScale::Linear: + set(ofMap(pct, 0, 1, obj->min, obj->max)); + break; + case ofParameterScale::Logarithmic:{ + auto offset = obj->min > 0 ? 0 : 1 - obj->min; + auto min = obj->min + offset; + auto max = obj->max + offset; + auto minv = log(min); + auto maxv = log(max); + auto scale = (maxv - minv); + set(exp(minv + scale * pct) - offset); + }break; + } +} + +template +template +typename std::enable_if::value, double>::type ofParameter::getPctScaled() const{ + switch(static_cast(obj->scale)){ + case ofParameterScale::Logarithmic:{ + auto offset = obj->min > 0 ? 0 : 1 - obj->min; + auto min = obj->min + offset; + auto max = obj->max + offset; + auto minv = log(min); + auto maxv = log(max); + auto scale = (maxv - minv); + return (log(obj->value + offset) - minv) / scale; + } + case ofParameterScale::Linear: + default: + return ofMap(obj->value, obj->min, obj->max, 0, 1); + } +} + +template +inline ParameterType ofParameter::operator++(int){ ParameterType r = obj->value; obj->value++; set(obj->value); @@ -1516,3 +1636,46 @@ template void ofReadOnlyParameter::setParent(ofParameterGroup & _parent) { parameter.setParent(_parent); } + + +/// Sets to false every other parameter when one of them is set to true +template +inline void ofSetMutuallyExclusive(ofParameter & p1, ofParameter & p2, Args&... parameters){ + ofSetMutuallyExclusive(p1, p2); + ofSetMutuallyExclusive(p1, parameters...); + ofSetMutuallyExclusive(p2, parameters...); +} + +/// Sets to false every other parameter when one of them is set to true +template<> +inline void ofSetMutuallyExclusive(ofParameter & p1, ofParameter & p2){ + p1.ownListener([p2](bool & enabled) mutable{ + if(enabled){ + p2.set(false); + } + }); + p2.ownListener([p1](bool & enabled) mutable{ + if(enabled){ + p1.set(false); + } + }); +} + +/// Sets the same value to every other passed parameter when any changes +template +inline void ofParameterLink(ofParameter & p1, ofParameter & p2, Args&... parameters){ + ofParameterLink(p1, p2); + ofParameterLink(p1, parameters...); + ofParameterLink(p2, parameters...); +} + +/// Sets the same value to every other passed parameter when any changes +template +inline void ofParameterLink(ofParameter & p1, ofParameter & p2){ + p1.ownListener([p2](T & v) mutable{ + p2.set(v); + }); + p2.ownListener([p1](T & v) mutable{ + p1.set(v); + }); +}