# Dynamic Properties

##### <a class="anchor" id="bkmrk--58"></a>How to attach a Dynamic Property to CanderaObject

An application may want to attach any kind of application specific data to an arbitrary CanderaObject. This is easily possible as CanderaObject derives from DynamicPropertyHost, which can store dynamic properties. Different to conventional object properties, a dynamic property can be attached to an object, without being declared in the object itself. Further, a dynamic property does not allocate memory unless its value is set explicitly and differs from its default value.

Find below a simple example how to attach an application specific object, acting as dynamic property, to an object that derives from DynamicPropertyHost, like e.g. CanderaObject, Node, Mesh, Appearance, Texture, only to name a few.

<div class="contents" id="bkmrk-if-possible-the-dyna"><div class="textblock">- If possible the dynamic property definition (see class LayouterDynamicProperties) should be contained in the source file and not in the header file. Otherwise, the code size may get unnecessarily increased due to the inability of Gcc and Multi linker to get rid of duplicate template instantiation in the object files.
- Dynamic properties 
    - can be set (see SetSize and SetLayoutDirection)
    - can be retrieved (see GetSize and GetLayoutDirection)
    - can be checked if they are set (see IsSizeSet and IsLayoutDirectionSet)
    - can be cleared (see ClearLayoutDirection)
    - have default values: C++ default initialization for simple types (see LayoutDirection) or specific values for complex types (see Size)
    - can have an optional change notification (see OnSizeChanged and OnLayoutDirectionChanged)
- A convenience interface should be provided to set, get, clear and check the dynamic property (see class Layouter). The dynamic property is only accessed via that interface.
- The DynamicPropertyHost (see class Layouter) has to provide the ParentProvider method for inherited dynamic properties. 
    - In the Layouter sample it is guaranteed by the Layouter convenience interface that only CanderaObject instances are supported. Hence, a static\_cast to CanderaObject is safe.

- Layouter.h ```
    class Layouter : public CanderaObject
    {
        …
        static void SetSize(CanderaObject& node, const Vector2& size);
        static const Vector2& GetSize(const CanderaObject& node);
        static bool IsSizeSet(const CanderaObject &node);
        …
        static void SetLayoutDirection(CanderaObject& node, <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a> direction);
        static <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a> GetLayoutDirection(const CanderaObject& node);
        static bool IsLayoutDirectionSet(const CanderaObject &node);
        static void ClearLayoutDirection(CanderaObject& node);
        …
        static const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_dynamic_properties_1_1_dynamic_property_host.html" title="Represents one host of dynamic properties. Inheriting from this class enables the definition of dynam...">Candera::DynamicProperties::DynamicPropertyHost</a>* ParentProvider(const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_dynamic_properties_1_1_dynamic_property_host.html" title="Represents one host of dynamic properties. Inheriting from this class enables the definition of dynam...">Candera::DynamicProperties::DynamicPropertyHost</a>* host);
        …
        static const Vector2& SizeDefault();
        …
        static void OnSizeChanged(DynamicPropertyHost* obj, const DynamicProperties::ValueChangedArgs<Vector2>& /*args*/) { InvalidateLayout(obj); }
        …
        static void OnLayoutDirectionChanged(DynamicPropertyHost* obj, const DynamicProperties::ValueChangedArgs<LayoutAlignment::LayoutDirection::Enum>& /*args*/) { InvalidateLayout(obj); }
        …
    };
    ```

- Layouter.cpp ```
    class LayouterDynamicProperties
    {
        …
        static void SetSize(CanderaObject& node, const Vector2& size)
        {
            static_cast<void>(node.SetValue(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(Size), size));
        }
     
        static const Vector2& GetSize(const CanderaObject& node)
        {
            return node.GetValue(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(Size));
        }
     
        static bool IsSizeSet(const CanderaObject &node)
        {
            return node.IsValueSet(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(Size));
        }
        …
        static void SetLayoutDirection(CanderaObject& node, <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a> direction)
        {
            static_cast<void>(node.SetValue(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(LayoutDirection), direction));
        }
     
        static <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a> GetLayoutDirection(const CanderaObject& node)
        {
            return node.GetValue(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(LayoutDirection));
        }
     
        static bool IsLayoutDirectionSet(const CanderaObject& node)
        {
            return node.IsValueSet(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(LayoutDirection));
        }
     
        static void ClearLayoutDirection(CanderaObject& node)
        {
            static_cast<void>(node.ClearValue(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga6f2de74138629f4edc7b62e6af84f51e">CdaDynamicPropertyInstance</a>(LayoutDirection)));
        }
        …
        <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga56cdb2a230d286a8fdcc9a09cc4560c0">CdaDynamicPropertiesDefinition</a>(<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_layouter.html" title="A non-zero padding applies space inside the element layout's width and height. The values can be set ...">Candera::Layouter</a>, CanderaObject);
            …
            <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga3d8637f7abaf54bd9e96872758a9c665">CdaDynamicProperty</a>(Size, Vector2);
                <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga0d189d9ab27d0d6307f917596483ec7e">CdaDynamicPropertyValueChangedCb</a>(&Layouter::OnSizeChanged);
                <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#gadd8042ac73891b129031af15f8827386">CdaDynamicPropertyDefaultValue</a>(Layouter::SizeDefault());
                …
            <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#gadac4ce20579ebcc0c3de673003762c36">CdaDynamicPropertyEnd</a>();
            …
            <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga3d8637f7abaf54bd9e96872758a9c665">CdaDynamicProperty</a>(LayoutDirection, <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a>);
                <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga0d189d9ab27d0d6307f917596483ec7e">CdaDynamicPropertyValueChangedCb</a>(&Layouter::OnLayoutDirectionChanged);
                …
            <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#gadac4ce20579ebcc0c3de673003762c36">CdaDynamicPropertyEnd</a>();
            …
        <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___dynamic_properties_base.html#ga7bdcb53ee21c7576202a7e19ed380602">CdaDynamicPropertiesEnd</a>();
    };
    …
    void Layouter::SetSize(CanderaObject& node, const Vector2& size)
    {
        LayouterDynamicProperties::SetSize(node, size);
    }
     
    const Vector2& Layouter::GetSize(const CanderaObject& node)
    {
        return LayouterDynamicProperties::GetSize(node);
    }
     
    bool Layouter::IsSizeSet(const CanderaObject &node)
    {
        return LayouterDynamicProperties::IsSizeSet(node);
    }
    …
    void Layouter::SetLayoutDirection(CanderaObject& node, <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a> direction)
    {
        LayouterDynamicProperties::SetLayoutDirection(node, direction);
    }
     
    <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___core2_d.html#gaa4cc311d76d6576e74f346fa9f6d87cb" title="TextNode2DRenderState enumeration defines the states a text can have in view of rendering the text...">LayoutAlignment::LayoutDirection::Enum</a> Layouter::GetLayoutDirection(const CanderaObject& node)
    {
        return LayouterDynamicProperties::GetLayoutDirection(node);
    }
     
    bool Layouter::IsLayoutDirectionSet(const CanderaObject& node)
    {
        return LayouterDynamicProperties::IsLayoutDirectionSet(node);
    }
     
    void Layouter::ClearLayoutDirection(CanderaObject& node)
    {
        LayouterDynamicProperties::ClearLayoutDirection(node);
    }
    …
    const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_dynamic_properties_1_1_dynamic_property_host.html" title="Represents one host of dynamic properties. Inheriting from this class enables the definition of dynam...">Candera::DynamicProperties::DynamicPropertyHost</a>* Layouter::ParentProvider(const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_dynamic_properties_1_1_dynamic_property_host.html" title="Represents one host of dynamic properties. Inheriting from this class enables the definition of dynam...">Candera::DynamicProperties::DynamicPropertyHost</a>* host) {
        CANDERA_SUPPRESS_LINT_FOR_NEXT_EXPRESSION(1774, "Layouter interface only allows CanderaObject for dynamic properties")
        const CanderaObject* object = static_cast<const CanderaObject*>(host);
    #ifdef CANDERA_2D_ENABLED
        const Node2D* node2D = Dynamic_Cast<const Node2D*>(object);
        if (0 != node2D) {
            return node2D->GetParent();
        }
    #endif
    #ifdef CANDERA_3D_ENABLED
        const Node* node = Dynamic_Cast<const Node*>(object);
        if (0 != node) {
            return node->GetParent();
        }
    #endif
        return 0;
    }
    void <a class="code" href="http://dev.doc.cgistudio.at/APILINK/group___behaviors_control.html#ggae7abc816df647d0ecbc280480fefb788aedec46ef1b6fa21d7dc275c4961918cb">Layouter::Layout</a>(const AbstractNodePointer& node)
    {
    …
            Vector2 nodeSize(Layouter::GetSize(*node.ToCanderaObject()));
    …
    }
    ```

</div></div>