546 lines
19 KiB
C++
546 lines
19 KiB
C++
|
|
|
|
#ifndef OFX_PROPERTY_SUITE_H
|
|
#define OFX_PROPERTY_SUITE_H
|
|
#include "ofxCore.h"
|
|
// Copyright OpenFX and contributors to the OpenFX project.
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
namespace OFX {
|
|
namespace Host {
|
|
namespace Property {
|
|
/// simple function to turn a thing into a std string
|
|
template<class T> inline std::string castToString(T i) {
|
|
std::ostringstream o;
|
|
o << i;
|
|
return o.str();
|
|
}
|
|
|
|
/// simple function to turn a string into an int
|
|
inline int stringToInt(const std::string &s) {
|
|
std::istringstream is(s);
|
|
int number;
|
|
is >> number;
|
|
return number;
|
|
}
|
|
|
|
/// simple function to turn a string into a double
|
|
inline double stringToDouble(const std::string &s) {
|
|
std::istringstream is(s);
|
|
double number;
|
|
is >> number;
|
|
return number;
|
|
}
|
|
|
|
// forward declarations
|
|
class Property;
|
|
class Set;
|
|
|
|
/// exception, representing an OfxStatus
|
|
class Exception {
|
|
OfxStatus _stat;
|
|
|
|
public:
|
|
/// ctor
|
|
Exception(OfxStatus stat) : _stat(stat)
|
|
{
|
|
}
|
|
|
|
/// get the status
|
|
OfxStatus getStatus() const
|
|
{
|
|
return _stat;
|
|
}
|
|
};
|
|
|
|
/// type of a property
|
|
enum TypeEnum {
|
|
eNone = -1,
|
|
eInt = 0,
|
|
eDouble = 1,
|
|
eString = 2,
|
|
ePointer = 3
|
|
};
|
|
|
|
/// type holder, for integers, used to template up int properties
|
|
struct IntValue {
|
|
typedef int APIType; ///< C type of the property that is passed across the raw API
|
|
typedef int APITypeConstless; ///< C type of the property that is passed across the raw API, without any const it
|
|
typedef int Type; ///< Type we actually hold and deal with the propery in everything by the raw API
|
|
typedef int ReturnType; ///< type to return from a function call
|
|
static const TypeEnum typeCode = eInt;
|
|
static int kEmpty;
|
|
};
|
|
|
|
/// type holder, for doubles, used to template up double properties
|
|
struct DoubleValue {
|
|
typedef double APIType;
|
|
typedef double APITypeConstless;
|
|
typedef double Type;
|
|
typedef double ReturnType; ///< type to return from a function call
|
|
static const TypeEnum typeCode = eDouble;
|
|
static double kEmpty;
|
|
};
|
|
|
|
/// type holder, for pointers, used to template up pointer properties
|
|
struct PointerValue {
|
|
typedef void *APIType;
|
|
typedef void *APITypeConstless;
|
|
typedef void *Type;
|
|
typedef void *ReturnType; ///< type to return from a function call
|
|
static const TypeEnum typeCode = ePointer;
|
|
static void *kEmpty;
|
|
};
|
|
|
|
/// type holder, for strings, used to template up string properties
|
|
struct StringValue {
|
|
typedef const char *APIType;
|
|
typedef char *APITypeConstless;
|
|
typedef std::string Type;
|
|
typedef const std::string &ReturnType; ///< type to return from a function call
|
|
static const TypeEnum typeCode = eString;
|
|
static std::string kEmpty;
|
|
};
|
|
|
|
/// array representing the names of the various types, in order of TypeEnum
|
|
extern const char *gTypeNames[];
|
|
|
|
/// Sits on a property and can override the local property value when a value is being fetched
|
|
/// only one of these can be in any property (as the thing has only a single value).
|
|
class GetHook {
|
|
public :
|
|
/// dtor
|
|
virtual ~GetHook()
|
|
{
|
|
}
|
|
|
|
/// We specialise this to do some magic so that it calls get string/int/double/pointer appropriately
|
|
/// this is what is called by the propertytemplate code to fetch values out of a hook.
|
|
template<class T> typename T::ReturnType getProperty(const std::string &name, int index=0) const;
|
|
|
|
/// We specialise this to do some magic so that it calls get int/double/pointer appropriately
|
|
/// this is what is called by the propertytemplate code to fetch values out of a hook.
|
|
template<class T> void getPropertyN(const std::string &name, typename T::APIType *values, int count) const;
|
|
|
|
/// override this to fetch a single value at the given index.
|
|
virtual const std::string& getStringProperty(const std::string &name, int index = 0) const;
|
|
|
|
/// override this to fetch a multiple values in a multi-dimension property
|
|
virtual void getStringPropertyN(const std::string &name, const char** values, int count) const;
|
|
|
|
/// override this to fetch a single value at the given index.
|
|
virtual int getIntProperty(const std::string &name, int index = 0) const;
|
|
|
|
/// override this to fetch a multiple values in a multi-dimension property
|
|
virtual void getIntPropertyN(const std::string &name, int *values, int count) const;
|
|
|
|
/// override this to fetch a single value at the given index.
|
|
virtual double getDoubleProperty(const std::string &name, int index = 0) const;
|
|
|
|
/// override this to fetch a multiple values in a multi-dimension property
|
|
virtual void getDoublePropertyN(const std::string &name, double *values, int count) const;
|
|
|
|
/// override this to fetch a single value at the given index.
|
|
virtual void *getPointerProperty(const std::string &name, int index = 0) const;
|
|
|
|
/// override this to fetch a multiple values in a multi-dimension property
|
|
virtual void getPointerPropertyN(const std::string &name, void **values, int count) const;
|
|
|
|
/// override this to fetch the dimension size.
|
|
virtual int getDimension(const std::string &name) const;
|
|
|
|
/// override this to handle a reset().
|
|
virtual void reset(const std::string &name);
|
|
};
|
|
|
|
/// Sits on a property and is called when the local property is being set.
|
|
/// It notify or notifyN is called whenever the plugin sets a property
|
|
/// Many of these can sit on a property, as various objects will need to know when a property
|
|
/// has been changed. On notification you should fetch properties with a 'raw' call, rather
|
|
/// than the standard calls, as you may be fetching through a getHook and you won't see
|
|
/// the local value that has been shoved into the property.
|
|
class NotifyHook {
|
|
public :
|
|
/// dtor
|
|
virtual ~NotifyHook() {}
|
|
|
|
/// override this to be notified when a property changes
|
|
/// \arg name is the name of the property just set
|
|
/// \arg singleValue is whether setProperty on a single index was call, otherwise N properties were set
|
|
/// \arg indexOrN is the index if single value is true, or the count if singleValue is false
|
|
virtual void notify(const std::string &name, bool singleValue, int indexOrN) = 0;
|
|
};
|
|
|
|
/// base class for all properties
|
|
class Property {
|
|
protected :
|
|
std::string _name; ///< name of this property
|
|
TypeEnum _type; ///< type of this property
|
|
int _dimension; ///< the fixed dimension of this property
|
|
bool _pluginReadOnly; ///< set is forbidden through suite: value may still change between get() calls
|
|
std::vector<NotifyHook *> _notifyHooks; ///< hooks to call whenever the property is set
|
|
GetHook *_getHook; ///< if we are not storing props locally, they are stored via fetching from here
|
|
|
|
friend class Set;
|
|
public :
|
|
/// ctor
|
|
Property(const std::string &name,
|
|
TypeEnum type,
|
|
int dimension = 1,
|
|
bool pluginReadOnly=false);
|
|
|
|
/// copy ctor
|
|
Property(const Property &other);
|
|
|
|
/// dtor
|
|
virtual ~Property()
|
|
{
|
|
}
|
|
|
|
/// is it read only?
|
|
bool getPluginReadOnly() const {return _pluginReadOnly; }
|
|
|
|
/// change the state of readonlyness
|
|
void setPluginReadOnly(bool v) {_pluginReadOnly = v;}
|
|
|
|
/// override this to return a clone of the property
|
|
virtual Property *deepCopy() = 0;
|
|
|
|
/// get the name of this property
|
|
const std::string &getName()
|
|
{
|
|
return _name;
|
|
}
|
|
|
|
/// get the type of this property
|
|
TypeEnum getType()
|
|
{
|
|
return _type;
|
|
}
|
|
|
|
/// add a notify hook
|
|
void addNotifyHook(NotifyHook *hook)
|
|
{
|
|
_notifyHooks.push_back(hook);
|
|
}
|
|
|
|
/// set the get hook
|
|
void setGetHook(GetHook *hook)
|
|
{
|
|
_getHook = hook;
|
|
}
|
|
|
|
/// call notify on the contained notify hooks
|
|
void notify(bool single, int indexOrN);
|
|
|
|
// get the current dimension of this property
|
|
virtual int getDimension() const = 0;
|
|
|
|
/// get the fixed dimension of this property
|
|
int getFixedDimension() const {
|
|
return _dimension;
|
|
}
|
|
|
|
/// are we a fixed dim property
|
|
bool isFixedSize() const
|
|
{
|
|
return _dimension != 0;
|
|
}
|
|
|
|
/// reset this property to the default
|
|
virtual void reset() = 0;
|
|
|
|
// get a string representing the value of this property at element nth
|
|
virtual std::string getStringValue(int nth) = 0;
|
|
};
|
|
|
|
/// this represents a generic property.
|
|
/// template parameter T is the type descriptor of the
|
|
/// type of property to model. the class holds an internal _value vector which can be used
|
|
/// to store the values. if set and get hooks are installed, these will be called instead
|
|
/// of using this variable.
|
|
/// Make sure that T::ReturnType is const if appropriate, as no extra qualifiers are applied here.
|
|
template<class T>
|
|
class PropertyTemplate : public Property
|
|
{
|
|
public :
|
|
typedef typename T::Type Type;
|
|
typedef typename T::ReturnType ReturnType;
|
|
typedef typename T::APIType APIType;
|
|
|
|
protected :
|
|
/// this is the present value of the property
|
|
std::vector<Type> _value;
|
|
|
|
/// this is the default value of the property
|
|
std::vector<Type> _defaultValue;
|
|
|
|
public :
|
|
/// constructor
|
|
PropertyTemplate(const std::string &name,
|
|
int dimension,
|
|
bool pluginReadOnly,
|
|
APIType defaultValue);
|
|
|
|
PropertyTemplate(const PropertyTemplate<T> &pt);
|
|
|
|
PropertyTemplate<T> *deepCopy() {
|
|
return new PropertyTemplate(*this);
|
|
}
|
|
|
|
virtual ~PropertyTemplate()
|
|
{
|
|
}
|
|
|
|
/// get the vector
|
|
const std::vector<Type> &getValues()
|
|
{
|
|
return _value;
|
|
}
|
|
|
|
// get multiple values
|
|
void getValueN(APIType *value, int count) const;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( disable : 4181 )
|
|
#endif
|
|
/// get one value
|
|
const ReturnType getValue(int index=0) const;
|
|
|
|
/// get one value, without going through the getHook
|
|
const ReturnType getValueRaw(int index=0) const;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( default : 4181 )
|
|
#endif
|
|
// get multiple values, without going through the getHook
|
|
void getValueNRaw(APIType *value, int count) const;
|
|
|
|
/// set one value
|
|
void setValue(const Type &value, int index=0);
|
|
|
|
/// set multiple values
|
|
void setValueN(const APIType *value, int count);
|
|
|
|
/// reset
|
|
void reset();
|
|
|
|
/// get the size of the vector
|
|
int getDimension() const;
|
|
|
|
/// return the value as a string
|
|
inline std::string getStringValue(int idx) {
|
|
return castToString(_value[idx]);
|
|
}
|
|
};
|
|
|
|
|
|
typedef PropertyTemplate<IntValue> Int; /// Our int property
|
|
typedef PropertyTemplate<DoubleValue> Double; /// Our double property
|
|
typedef PropertyTemplate<StringValue> String; /// Our string property
|
|
typedef PropertyTemplate<PointerValue> Pointer; /// Our pointer property
|
|
|
|
/// A class that is used to initialise a property set. Feed in an array of these to
|
|
/// a property and it will construct a bunch of properties. Terminate such an array
|
|
/// with an empty (all zero) set.
|
|
struct PropSpec {
|
|
const char *name; ///< name of the property
|
|
TypeEnum type; ///< type
|
|
int dimension; ///< fixed dimension of the property, set to zero if variable dimension
|
|
bool readonly; ///< is the property plug-in read only
|
|
const char *defaultValue; ///< Default value as a string. Pointers are ignored and always null.
|
|
};
|
|
static const PropSpec propSpecEnd = {0, eNone, 0, false, 0};
|
|
|
|
/// A std::map of properties by name
|
|
typedef std::map<std::string, Property *> PropertyMap;
|
|
|
|
|
|
//................................................................................
|
|
/// Class that holds a set of properties and manipulates them
|
|
/// The 'fetch' methods return a property object.
|
|
/// The 'get' methods return a property value
|
|
class Set {
|
|
private :
|
|
static const int kMagic = 0x12082007; ///< magic number for property sets, and Connie's birthday :-)
|
|
const int _magic; ///< to check for handles being nice
|
|
|
|
protected :
|
|
PropertyMap _props; ///< Our properties.
|
|
|
|
/// chained property set, which is read only
|
|
/// these are searched on a get if not found
|
|
/// on a local search
|
|
Set *_chainedSet;
|
|
|
|
/// hide assignment
|
|
void operator=(const Set &);
|
|
|
|
/// set a particular property
|
|
template<class T> void setProperty(const std::string &property, int index, const typename T::Type &value);
|
|
|
|
/// set the first N of a particular property
|
|
template<class T> void setPropertyN(const std::string &property, int count, const typename T::APIType *value);
|
|
|
|
/// get a particular property
|
|
template<class T> typename T::ReturnType getProperty(const std::string &property, int index) const;
|
|
|
|
/// get the first N of a particular property
|
|
template<class T> void getPropertyN(const std::string &property, int index, typename T::APIType *v) const;
|
|
|
|
/// get a particular property without going through any getHook
|
|
template<class T> typename T::ReturnType getPropertyRaw(const std::string &property, int index) const;
|
|
|
|
/// get a particular property without going through any getHook
|
|
template<class T> void getPropertyRawN(const std::string &property, int count, typename T::APIType *v) const;
|
|
|
|
public :
|
|
/// take an array of of PropSpecs (which must be terminated with an entry in which
|
|
/// ->name is null), and turn these into a Set
|
|
explicit Set(const PropSpec *);
|
|
|
|
/// deep copies the property set
|
|
explicit Set(const Set &);
|
|
|
|
/// empty ctor
|
|
explicit Set();
|
|
|
|
/// destructor
|
|
virtual ~Set();
|
|
|
|
/// adds a bunch of properties from PropSpec
|
|
void addProperties(const PropSpec *);
|
|
|
|
/// add one new property
|
|
void createProperty(const PropSpec &s);
|
|
|
|
/// add one new property
|
|
void addProperty(Property *prop);
|
|
|
|
/// set the chained property set
|
|
void setChainedSet(Set *s) {_chainedSet = s;}
|
|
|
|
/// grab the internal properties map
|
|
const PropertyMap &getProperties() const
|
|
{
|
|
return _props;
|
|
}
|
|
|
|
/// set the get hook for a particular property. users may need to call particular
|
|
/// specialised versions of this.
|
|
void setGetHook(const std::string &s, GetHook *ghook) const;
|
|
|
|
/// add a set hook for a particular property. users may need to call particular
|
|
/// specialised versions of this.
|
|
void addNotifyHook(const std::string &name, NotifyHook *hook) const;
|
|
|
|
/// Fetchs a pointer to a property of the given name, following the property chain if the
|
|
/// 'followChain' arg is not false.
|
|
Property *fetchProperty(const std::string &name, bool followChain = false) const;
|
|
|
|
/// get property with the particular name and type. if the property is
|
|
/// missing or is of the wrong type, return an error status. if this is a sloppy
|
|
/// property set and the property is missing, a new one will be created of the right
|
|
/// type
|
|
template<class T> bool fetchTypedProperty(const std::string &name, T *&prop, bool followChain = false) const;
|
|
|
|
/// retrieve the nameed string property
|
|
String *fetchStringProperty(const std::string &name, bool followChain = false) const;
|
|
|
|
/// retrieve the named double property
|
|
Double *fetchDoubleProperty(const std::string &name, bool followChain = false) const;
|
|
|
|
/// retrieve the named double property
|
|
Pointer *fetchPointerProperty(const std::string &name, bool followChain = false) const;
|
|
|
|
/// retrieve the named double property
|
|
Int *fetchIntProperty(const std::string &name, bool followChain = false) const;
|
|
|
|
|
|
|
|
/// get a particular int property without fetching via a get hook, useful for notifies
|
|
int getIntPropertyRaw(const std::string &property, int index = 0) const;
|
|
|
|
/// get a particular double property without fetching via a get hook, useful for notifies
|
|
double getDoublePropertyRaw(const std::string &property, int index = 0) const;
|
|
|
|
/// get a particular pointer property without fetching via a get hook, useful for notifies
|
|
void *getPointerPropertyRaw(const std::string &property, int index = 0) const;
|
|
|
|
/// get a particular string property
|
|
const std::string &getStringPropertyRaw(const std::string &property, int index = 0) const;
|
|
|
|
/// get the value of a particular string property
|
|
const std::string &getStringProperty(const std::string &property, int index = 0) const;
|
|
|
|
/// get the value of a particular int property
|
|
int getIntProperty(const std::string &property, int index = 0) const;
|
|
|
|
/// get the value of a particular double property
|
|
void getIntPropertyN(const std::string &property, int *v, int N) const;
|
|
|
|
/// get the value of a particular double property
|
|
double getDoubleProperty(const std::string &property, int index = 0) const;
|
|
|
|
/// get the value of a particular double property
|
|
void getDoublePropertyN(const std::string &property, double *v, int N) const;
|
|
|
|
/// get the value of a particular pointer property
|
|
void *getPointerProperty(const std::string &property, int index = 0) const;
|
|
|
|
|
|
|
|
/// set a particular string property without fetching via a get hook, useful for notifies
|
|
void setStringProperty(const std::string &property, const std::string &value, int index = 0);
|
|
|
|
/// get a particular int property
|
|
void setIntProperty(const std::string &property, int v, int index = 0);
|
|
|
|
/// get a particular double property
|
|
void setIntPropertyN(const std::string &property, const int *v, int N);
|
|
|
|
/// get a particular double property
|
|
void setDoubleProperty(const std::string &property, double v, int index = 0);
|
|
|
|
/// get a particular double property
|
|
void setDoublePropertyN(const std::string &property, const double *v, int N);
|
|
|
|
/// get a particular double property
|
|
void setPointerProperty(const std::string &property, void *v, int index = 0);
|
|
|
|
|
|
|
|
/// get the dimension of a particular property
|
|
int getDimension(const std::string &property) const;
|
|
|
|
/// is the given string one of the values of a multi-dimensional string prop
|
|
/// this returns a non negative index if it is found, otherwise, -1
|
|
int findStringPropValueIndex(const std::string &propName,
|
|
const std::string &propValue) const;
|
|
|
|
|
|
/// get a handle on this object for passing to the C API
|
|
OfxPropertySetHandle getHandle() const
|
|
{
|
|
return (OfxPropertySetHandle)this;
|
|
}
|
|
|
|
/// is this a nice property set, or a dodgy pointer passed back to us
|
|
bool verifyMagic() { return _magic == kMagic; }
|
|
};
|
|
|
|
|
|
/// return the OFX function suite that manages properties
|
|
const void *GetSuite(int version);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|