1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #ifndef __OGRE_PROPERTY_H__
29 #define __OGRE_PROPERTY_H__
30 
31 #include "OgrePropertyPrerequisites.h"
32 #include "OgreAny.h"
33 #include "OgreString.h"
34 #include "OgreException.h"
35 #include "OgreQuaternion.h"
36 #include "OgreMatrix4.h"
37 
38 #include <functional>
39 
40 /** \addtogroup Optional
41 *  @{
42 */
43 /** \defgroup Property Property
44 * Associate values of arbitrary type with names
45 *  @{
46 */
47 
48 /** @file
49     OGRE's property system allows you to associate values of arbitrary type with
50     names, and have those values exposed via a self-describing interface. Unlike
51     Ogre::StringInterface, the values are passed as their native types without
52     needing conversion to or from strings; they are simply wrapped in an Ogre::Any
53     and casts are performed to access them.
54     @par
55     Property values are actually not stored in this system; instead the property
56     definitions reference getter & setter methods which provide the 'backing' for
57     the property. This means you can directly expose features of your classes as properties
58     without any duplication.
59     @par
60     There are two aspects to exposing a property on your class. One is exposing
61     the definition of the property (PropertyDef), which should be shared between
62     all instances and probably stored in a static PropertyDefMap somewhere. The second
63     is the instance 'wiring' which ensures that a call to set a property calls
64     a method on this particular instance of the class; this is formed by a number of
65     Property instances, contained in a PropertySet. Each Property has an explicit
66     binding to getter and setter instance methods.
67     @par
68     So, here's an example of setting up properties on an instance:
69 
70     @code
71     // Make sure the property definition is created
72     // propertyDefs is a variable of type PropertyDefMap, shared between instances
73     PropertyDefMap::iterator defi = propertyDefs.find("name");
74     if (defi == propertyDefs.end())
75     {
76         defi = propertyDefs.insert(PropertyDefMap::value_type("name",
77             PropertyDef("name",
78                 "The name of the object.", PROP_STRING))).first;
79     }
80     // This has established the property definition, and its description.
81     // Now, we need to 'wire' a property instance for this object instance
82     // We assume the class is called 'Foo' and the instance is pointed to by a variable called 'inst'
83     // 'props' is a PropertySet, specific to the instance
84     props.addProperty(
85         OGRE_NEW Property<String>(&(defi->second),
86             std::bind(&Foo::getName, inst),
87             std::bind(&Foo::setName, inst, _1)));
88 
89     @endcode
90 
91 */
92 
93 /** @} */
94 /** @} */
95 namespace Ogre
96 {
97     using std::function;
98 
99     /** \addtogroup Optional
100     *  @{
101     */
102     /** \addtogroup Property
103     *  @{
104     */
105 
106     /// The type of a property
107     enum PropertyType
108     {
109         PROP_SHORT = 0,
110         PROP_UNSIGNED_SHORT = 1,
111         PROP_INT = 2,
112         PROP_UNSIGNED_INT = 3,
113         PROP_LONG = 4,
114         PROP_UNSIGNED_LONG = 5,
115         PROP_REAL = 6,
116         PROP_STRING = 7,
117         PROP_VECTOR2 = 8,
118         PROP_VECTOR3 = 9,
119         PROP_VECTOR4 = 10,
120         PROP_COLOUR = 11,
121         PROP_BOOL = 12,
122         PROP_QUATERNION = 13,
123         PROP_MATRIX3 = 14,
124         PROP_MATRIX4 = 15,
125 
126         PROP_UNKNOWN = 999
127     };
128 
129     typedef GeneralAllocatedObject PropertyAlloc;
130 
131     /** Definition of a property of an object.
132     @remarks
133     This definition is shared between all instances of an object and therefore
134     has no value. Property contains values.
135     */
136     class _OgrePropertyExport PropertyDef : public PropertyAlloc
137     {
138     public:
139 
140         /** Construct a property.
141         @param name The name of the property
142         @param desc A (potentially) long description of the property
143         @param pType The type of the property
144         */
PropertyDef(const String & name,const String & desc,PropertyType pType)145         PropertyDef(const String& name, const String& desc, PropertyType pType)
146             : mName(name), mDesc(desc), mType(pType) {}
147 
148         /// Get the name of the property
getName()149         const String& getName() const { return mName; }
150 
151         /// Get the description of the property
getDescription()152         const String& getDescription() const { return mDesc; }
153 
154         /// Get the type of the property
getType()155         PropertyType getType() const { return mType; }
156 
157         /// Get a string name of a property type
158         static const String& getTypeName(PropertyType theType);
159 
getTypeForValue(const short & val)160         static PropertyType getTypeForValue(const short& val) { return PROP_SHORT; }
getTypeForValue(const unsigned short & val)161         static PropertyType getTypeForValue(const unsigned short& val) { return PROP_UNSIGNED_SHORT; }
getTypeForValue(const int & val)162         static PropertyType getTypeForValue(const int& val) { return PROP_INT; }
getTypeForValue(const unsigned int & val)163         static PropertyType getTypeForValue(const unsigned int& val) { return PROP_UNSIGNED_INT; }
getTypeForValue(const long & val)164         static PropertyType getTypeForValue(const long& val) { return PROP_LONG; }
getTypeForValue(const unsigned long & val)165         static PropertyType getTypeForValue(const unsigned long& val) { return PROP_UNSIGNED_LONG; }
getTypeForValue(const Real & val)166         static PropertyType getTypeForValue(const Real& val) { return PROP_REAL; }
getTypeForValue(const String & val)167         static PropertyType getTypeForValue(const String& val) { return PROP_STRING; }
getTypeForValue(const Vector2 & val)168         static PropertyType getTypeForValue(const Vector2& val) { return PROP_VECTOR2; }
getTypeForValue(const Vector3 & val)169         static PropertyType getTypeForValue(const Vector3& val) { return PROP_VECTOR3; }
getTypeForValue(const Vector4 & val)170         static PropertyType getTypeForValue(const Vector4& val) { return PROP_VECTOR4; }
getTypeForValue(const ColourValue & val)171         static PropertyType getTypeForValue(const ColourValue& val) { return PROP_COLOUR; }
getTypeForValue(const bool & val)172         static PropertyType getTypeForValue(const bool& val) { return PROP_BOOL; }
getTypeForValue(const Quaternion & val)173         static PropertyType getTypeForValue(const Quaternion& val) { return PROP_QUATERNION; }
getTypeForValue(const Matrix3 & val)174         static PropertyType getTypeForValue(const Matrix3& val) { return PROP_MATRIX3; }
getTypeForValue(const Matrix4 & val)175         static PropertyType getTypeForValue(const Matrix4& val) { return PROP_MATRIX4; }
176 
177     protected:
178         // no default construction
PropertyDef()179         PropertyDef() {}
180 
181         String mName;
182         String mDesc;
183         PropertyType mType;
184 
185     };
186 
187     /// Map from property name to shared definition
188     typedef std::map<String, PropertyDef> PropertyDefMap;
189 
190     /** Base interface for an instance of a property.
191     */
192     class _OgrePropertyExport PropertyBase : public PropertyAlloc
193     {
194     public:
195         /// Constructor
PropertyBase(PropertyDef * def)196         PropertyBase(PropertyDef* def) : mDef(def) {}
~PropertyBase()197         virtual ~PropertyBase() {}
198 
199         /// Get the name of the property
getName()200         const String& getName() const { return mDef->getName(); }
201 
202         /// Get the description of the property
getDescription()203         const String& getDescription() const { return mDef->getDescription(); }
204 
205         /// Get the type of the property
getType()206         PropertyType getType() const { return mDef->getType(); }
207 
208         /// Return the current value as an Any
209         virtual Ogre::Any getValue() const = 0;
210 
211     protected:
212         // disallow default construction
PropertyBase()213         PropertyBase() {}
214         PropertyDef* mDef;
215 
216     };
217 
218     /** Property instance with passthrough calls to a given object. */
219     template <typename T>
220     class Property : public PropertyBase
221     {
222     public:
223         typedef T value_type;
224         typedef function< T (void) > getter_func;
225         typedef function< void (T) > setter_func;
226 
227         /** Construct a property which is able to directly call a given
228         getter and setter on a specific object instance, via functors.
229         */
Property(PropertyDef * def,getter_func getter,setter_func setter)230         Property(PropertyDef* def, getter_func getter, setter_func setter)
231             : PropertyBase(def)
232             , mGetter(getter)
233             , mSetter(setter)
234         {
235         }
236 
237         /** Set the property value.
238         */
set(T val)239         virtual void set(T val)
240         {
241             mSetter(val);
242         }
243 
get()244         virtual T get() const
245         {
246             return mGetter();
247         }
248 
getValue()249         Ogre::Any getValue() const
250         {
251             return Ogre::Any(get());
252         }
253 
254     protected:
255         // disallow default construction
Property()256         Property() {}
~Property()257         ~Property() {}
258 
259         getter_func mGetter;
260         setter_func mSetter;
261     };
262 
263     /** A simple structure designed just as a holder of property values between
264     the instances of objects they might target. There is just enough information
265     here to be able to interpret the results accurately but no more.
266     */
267     struct PropertyValue
268     {
269         PropertyType propType;
270         Ogre::Any val;
271     };
272     /// Defines a transferable map of properties using wrapped value types (Ogre::Any)
273     typedef std::map<String, PropertyValue> PropertyValueMap;
274 
275 
276     /** Defines a complete set of properties for a single object instance.
277     */
278     class _OgrePropertyExport PropertySet : public PropertyAlloc
279     {
280     public:
281         PropertySet();
282         ~PropertySet();
283 
284         /** Adds a property to this set.
285         @remarks
286         The PropertySet is responsible for deleting this object.
287         */
288         void addProperty(PropertyBase* prop);
289 
290         /** Gets the property object for a given property name.
291         @remarks
292         Note that this property will need to be cast to a templated property
293         compatible with the type you will be setting. You might find the
294         overloaded set and get<type> methods quicker if
295         you already know the type.
296         */
297         PropertyBase* getProperty(const String& name) const;
298 
299         /** Reports whether this property set contains a named property. */
300         bool hasProperty(const String& name) const;
301 
302         /** Removes the named property from the property set. */
303         void removeProperty(const String& name);
304 
305         typedef std::map<String, PropertyBase*> PropertyMap;
306 
307         /** Gets an independently usable collection of property values from the
308         current state.
309         */
310         PropertyValueMap getValueMap() const;
311 
312         /** Sets the current state from a given value map.
313         */
314         void setValueMap(const PropertyValueMap& values);
315 
316         /** Get a named property value.
317         */
318         template<typename T>
getValue(const String & name,T & value)319         void getValue(const String& name, T& value) const
320         {
321             getPropertyImpl(name, value, PropertyDef::getTypeForValue(value));
322         }
323 
324         /** Set a named property value (via pointer to avoid copy).
325         */
326         template<typename T>
setValue(const String & name,const T * value)327         void setValue(const String& name, const T* value)
328         {
329             setPropertyImpl(name, *value, PropertyDef::getTypeForValue(*value));
330         }
331         /** Set a named property value.
332         */
333         template<typename T>
setValue(const String & name,T value)334         void setValue(const String& name, T value)
335         {
336             setPropertyImpl(name, value, PropertyDef::getTypeForValue(value));
337         }
338         /** Special-case char*, convert to String automatically.
339         */
setValue(const String & name,const char * pChar)340         void setValue(const String& name, const char* pChar)
341         {
342             String v(pChar);
343             setPropertyImpl(name, v, PROP_STRING);
344         }
345 
346 
347     protected:
348         PropertyMap mPropertyMap;
349 
350         /// Set a named property value, internal implementation (type match required)
351         template <typename T>
setPropertyImpl(const String & name,const T & val,PropertyType typeCheck)352         void setPropertyImpl(const String& name, const T& val, PropertyType typeCheck)
353         {
354             PropertyBase* baseProp = getProperty(name);
355             if (baseProp->getType() != typeCheck)
356             {
357                 StringStream msg;
358                 msg << "Property error: type passed in: '" << PropertyDef::getTypeName(typeCheck)
359                     << "', type of property: '" << PropertyDef::getTypeName(baseProp->getType()) << "'";
360                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, msg.str(), "PropertySet::setPropertyImpl");
361             }
362             static_cast<Property<T>*>(baseProp)->set(val);
363         }
364 
365         /// Get a named property value, internal implementation (type match required)
366         template <typename T>
getPropertyImpl(const String & name,T & refVal,PropertyType typeCheck)367         void getPropertyImpl(const String& name, T& refVal, PropertyType typeCheck) const
368         {
369             PropertyBase* baseProp = getProperty(name);
370             if (baseProp->getType() != typeCheck)
371             {
372                 StringStream msg;
373                 msg << "Property error: type requested: '" << PropertyDef::getTypeName(typeCheck)
374                     << "', type of property: '" << PropertyDef::getTypeName(baseProp->getType()) << "'";
375                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, msg.str(), "PropertySet::getPropertyImpl");
376             }
377             refVal = static_cast<Property<T>*>(baseProp)->get();
378         }
379 
380     };
381 
382     /** @} */
383     /** @} */
384 
385 }
386 
387 #endif
388