diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h
index aed1f96afb..93ed912bbd 100644
--- a/include/openspace/properties/property.h
+++ b/include/openspace/properties/property.h
@@ -39,42 +39,216 @@ namespace properties {
class PropertyOwner;
+/**
+ * A property encapsulates a value which should be user-changeable. A property almost
+ * always belongs to a PropertyOwner who has taken ownership (setPropertyOwner) of the
+ * Property. Per PropertyOwner, the identifier needs to be unique and can be
+ * used as a URI. This class is an abstract base class and each subclass (most notable
+ * TemplateProperty) needs to implement the methods Property::className, Property::get,
+ * Property::set, Property::type(), Property::getLua, Property::setLua, and
+ * Property::typeLua to make full use of the infrastructure.
+ * The most common types can be implemented by creating a specialized instantiation of
+ * TemplateProperty, which provides default implementations for these methods.
+ *
+ * The onChange method can be used by the PropertyOwner to listen to changes that happen
+ * to the Property. The parameter is a function object that gets called after new value
+ * has been set.
+ * The metaData allows the developer to specify additional information about the Property
+ * which might be used in GUI representations. One example would be a glm::vec4 property,
+ * (Vec4Property) that can either represent a 4-dimensional position, a powerscaled
+ * coordinate, a light position, or other things, requiring different GUI representations.
+ * \see TemplateProperty
+ * \see PropertyOwner
+ */
class Property {
public:
+ /**
+ * The constructor for the property. The identifier needs to be unique
+ * for each PropertyOwner. The guiName will be stored in the metaData
+ * to be accessed by the GUI elements using the guiName key. The default
+ * visibility settings is true, whereas the default read-only state is
+ * false.
+ * \param identifier A unique identifier for this property. It has to be unique to the
+ * PropertyOwner
+ * \param guiName The human-readable GUI name for this Property
+ */
Property(std::string identifier, std::string guiName);
+
+ /**
+ * The destructor taking care of deallocating all unused memory. This method will not
+ * remove the Property from the PropertyOwner.
+ */
virtual ~Property();
- //virtual Property* create() const = 0;
+ /**
+ * This method returns the class name of the Property. The method is used by the
+ * TemplateFactory to create new instances of Propertys. The returned value is almost
+ * always identical to the C++ class name of the derived class.
+ * \return The class name of the Property
+ */
virtual std::string className() const = 0;
+ /**
+ * This method returns the encapsulated value of the Property to the caller. The type
+ * that is returned is determined by the type function and is up to the developer of
+ * the derived class. The default implementation returns an empty boost::any object.
+ * \return The value that is encapsulated by this Property, or an empty boost::any
+ * object if the method was not overritten.
+ */
virtual boost::any get() const;
- virtual void set(boost::any value);
- virtual const std::type_info& type() const;
+ /**
+ * Sets the value encapsulated by this Property to the value passed to
+ * this function. It is the caller's responsibility to ensure that the type contained
+ * in value is compatible with the concrete subclass of the Property. The
+ * method Property::type will return the desired type for the Property. The default
+ * implementation of this method ignores the input.
+ * \param value The new value that should be stored in this Property
+ */
+ virtual void set(boost::any value);
+
+ /**
+ * This method returns the type that is requested by this Property for the set method.
+ * The default implementation returns the type of void.
+ * \return The type that is requested by this Property's Property::set method
+ */
+ virtual const std::type_info& type() const;
+
+ /**
+ * This method encodes the encapsulated value of this Property at the top of the Lua
+ * stack. The specific details of this serialization is up to the property developer
+ * as long as the rest of the stack is unchanged. The implementation has to be
+ * synchronized with the Property::setLua method. The default implementation is a
+ * no-op.
+ * \param state The Lua state to which the value will be encoded
+ * \return true if the encoding succeeded, false otherwise
+ */
virtual bool getLua(lua_State* state) const;
+
+ /**
+ * This method sets the value encapsulated by this Property by deserializing the value
+ * on top of the passed Lua stack. The specific details of the deserialization are up
+ * to the Property developer, but they must only depend on the top element of the
+ * stack and must leave all other elements unchanged. The implementation has to be
+ * synchronized with the Property::getLua method. The default implementation is a
+ * no-op.
+ * \param state The Lua state from which the value will be decoded
+ * \return true if the decoding and setting of the value succeeded,
+ * false otherwise
+ */
virtual bool setLua(lua_State* state);
+
+ /**
+ * Returns the Lua type that will be put onto the stack in the Property::getLua method
+ * and which will be consumed by the Property::setLua method. The returned value
+ * can belong to the set of Lua types: LUA_TNONE, LUA_TNIL,
+ * LUA_TBOOLEAN, LUA_TLIGHTUSERDATA,
+ * LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE,
+ * LUA_TFUNCTION, LUA_TUSERDATA, or
+ * LUA_TTHREAD. The default implementation will return
+ * LUA_TNONE.
+ * \return The Lua type that will be consumed or produced by the Property::getLua and
+ * Property::setLua methods.
+ */
virtual int typeLua() const;
+ /**
+ * This method registers a callback function that will be called every
+ * time if either Property:set or Property::setLua was called with a value that is
+ * different from the previously stored value. The callback can be removed my passing
+ * an empty std::function object.
+ * \param callback The callback function that is called when the encapsulated type has
+ * been successfully changed by either the Property::set or Property::setLua methods.
+ */
virtual void onChange(std::function callback);
+ /**
+ * This method returns the unique identifier of this Property.
+ * \return The unique identifier of this Property
+ */
const std::string& identifier() const;
- const std::string& guiName() const;
+ /**
+ * Returns the PropertyOwner of this Property or nullptr, if it does not
+ * have an owner.
+ *\ return The Property of this Property
+ */
PropertyOwner* owner() const;
- void setPropertyOwner(PropertyOwner* owner);
+ /**
+ * Assigned the Property to a new PropertyOwner. This method does not inform the
+ * PropertyOwner of this action.
+ * \param owner The new PropertyOwner for this Property
+ */
+ void setPropertyOwner(PropertyOwner* owner);
+
+ /**
+ * Returns the human-readable GUI name for this Property that has been set in the
+ * constructor. This method returns the same value as accessing the metaData object
+ * and requesting the std::string stored for the guiName
+ * key.
+ * \return The human-readable GUI name for this Property
+ */
+ const std::string& guiName() const;
+
+ /**
+ * Sets the identifier of the group that this Property belongs to. Property groups can
+ * be used, for example, by GUI application to visually group different properties,
+ * but it has no impact on the Property itself. The default value for the groupID is
+ * "".
+ * \param groupId The group id that this property should belong to
+ */
void setGroupIdentifier(std::string groupId);
+
+ /**
+ * Returns the group idenfier that this Property belongs to, or "" if it
+ * belongs to no group.
+ * \return The group identifier that this Property belongs to
+ */
std::string groupIdentifier() const;
+ /**
+ * Determines a hint if this Property should be visible, or hidden. Each application
+ * accessing the properties is free to ignore this hint. It is stored in the metaData
+ * Dictionary with the key: isVisible. The default value is
+ * true.
+ * \param state true if the Property should be visible,
+ * false otherwise.
+ */
void setVisible(bool state);
- bool isVisible() const;
- void setReadOnly(bool state);
- bool isReadOnly() const;
+ /**
+ * This method determines if this Property should be read-only in external
+ * applications. This setting is only a hint and does not need to be followed by GUI
+ * applications and does not have any effect on the Property::set or Property::setLua
+ * methods. The value is stored in the metaData Dictionary with the key:
+ * isReadOnly. The default value is false.
+ * \param state true if the Property should be read only,
+ * false otherwise
+ */
+ void setReadOnly(bool state);
+ /**
+ * This method allows the developer to give hints to the GUI about different
+ * representations for the GUI. The same Property (for example Vec4Property) can be
+ * used in different ways, each requiring a different input method. These values are
+ * stored in the metaData object using the views. prefix in front of the
+ * option parameter. See Property::ViewOptions for a default list of
+ * possible options. As these are only hints, the GUI is free to ignore any suggestion
+ * by the developer.
+ * \param option The view option that should be modified
+ * \param value Determines if the view option should be active (true) or
+ * deactivated (false)
+ */
void setViewOption(std::string option, bool value = true);
- bool viewOption(const std::string& option) const;
+ /**
+ * Default view options that can be used in the Property::setViewOption method. The
+ * values are: Property::ViewOptions::Color = color,
+ * Property::ViewOptions::LightPosition = lightPosition,
+ * Property::ViewOptions::PowerScaledScalar = powerScaledScalar, and
+ * Property::ViewOptions::PowerScaledCoordinate = powerScaledCoordinate.
+ */
struct ViewOptions {
static const std::string Color;
static const std::string LightPosition;
@@ -82,18 +256,32 @@ public:
static const std::string PowerScaledCoordinate;
};
+ /**
+ * Returns the metaData that contains all information for external applications to
+ * correctly display information about the Property. No information that is stored in
+ * this Dictionary is necessary for the programmatic use of the Property.
+ * \return The Dictionary containing all meta data information about this Property
+ */
const ghoul::Dictionary& metaData() const;
protected:
- void notifyListeners();
+ /**
+ * This method must be called by all subclasses whenever the encapsulated value has
+ * changed and a potential listener has to be informed.
+ */
+ void notifyListener();
- PropertyOwner* _owner;
+ /// The PropetyOwner this Property belongs to, or nullptr
+ PropertyOwner* _owner;
+ /// The identifier for this Property
std::string _identifier;
- std::string _guiName;
+
+ /// The Dictionary containing all meta data necessary for external applications
ghoul::Dictionary _metaData;
- std::vector> _onChangeCallbacks;
+ /// The callback function that will be invoked whenever the encapsulated value changes
+ std::function _onChangeCallback;
};
} // namespace properties
diff --git a/include/openspace/properties/templateproperty.inl b/include/openspace/properties/templateproperty.inl
index 2db1902329..ae81fd4836 100644
--- a/include/openspace/properties/templateproperty.inl
+++ b/include/openspace/properties/templateproperty.inl
@@ -133,7 +133,7 @@ template
void TemplateProperty::set(boost::any value) {
try {
_value = boost::any_cast(std::move(value));
- notifyListeners();
+ notifyListener();
}
catch (boost::bad_any_cast&) {
LERRORC("TemplateProperty", "Illegal cast from '" << value.type().name()
diff --git a/src/properties/property.cpp b/src/properties/property.cpp
index 7ea90bcbe7..f00890f9bd 100644
--- a/src/properties/property.cpp
+++ b/src/properties/property.cpp
@@ -30,9 +30,12 @@ namespace openspace {
namespace properties {
namespace {
+ const std::string _metaDataKeyGuiName = "guiName";
const std::string _metaDataKeyGroup = "group";
const std::string _metaDataKeyVisible = "isVisible";
const std::string _metaDataKeyReadOnly = "isReadOnly";
+
+ const std::string _metaDataKeyViewPrefix = "view.";
}
const std::string Property::ViewOptions::Color = "color";
@@ -43,9 +46,9 @@ const std::string Property::ViewOptions::PowerScaledScalar = "powerScaledScalar"
Property::Property(std::string identifier, std::string guiName)
: _identifier(std::move(identifier))
- , _guiName(std::move(guiName))
{
setVisible(true);
+ _metaData.setValue(_metaDataKeyGuiName, std::move(guiName));
}
Property::~Property() {}
@@ -77,7 +80,9 @@ int Property::typeLua() const {
}
const std::string& Property::guiName() const {
- return _guiName;
+ std::string result = "";
+ _metaData.getValue(_metaDataKeyGuiName, result);
+ return std::move(result);
}
void Property::setGroupIdentifier(std::string groupId) {
@@ -94,30 +99,12 @@ void Property::setVisible(bool state) {
_metaData.setValue(_metaDataKeyVisible, state);
}
-bool Property::isVisible() const {
- bool result = false;
- _metaData.getValue(_metaDataKeyVisible, result);
- return result;
-}
-
void Property::setReadOnly(bool state) {
_metaData.setValue(_metaDataKeyReadOnly, state);
}
-bool Property::isReadOnly() const {
- bool result = false;
- _metaData.getValue(_metaDataKeyReadOnly, result);
- return result;
-}
-
void Property::setViewOption(std::string option, bool value) {
- _metaData.setValue("view." + option, value, true);
-}
-
-bool Property::viewOption(const std::string& option) const {
- bool result = false;
- _metaData.getValue("view." + option, result);
- return result;
+ _metaData.setValue(_metaDataKeyViewPrefix + option, value, true);
}
const ghoul::Dictionary& Property::metaData() const {
@@ -125,7 +112,7 @@ const ghoul::Dictionary& Property::metaData() const {
}
void Property::onChange(std::function callback) {
- _onChangeCallbacks.push_back(std::move(callback));
+ _onChangeCallback = std::move(callback);
}
@@ -139,9 +126,8 @@ void Property::setPropertyOwner(PropertyOwner* owner)
_owner = owner;
}
-void Property::notifyListeners() {
- for (std::function& f : _onChangeCallbacks)
- f();
+void Property::notifyListener() {
+ _onChangeCallback();
}
} // namespace properties