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