# CGI-Studio Default Behaviors

CGI-Studio already provides multiple Behaviors by default which can already be used in projects. While they are also just Behaviors the follow a new concept for development which has been made possible by the new features of Behaviors.

<div class="header" id="bkmrk-basic-concept"><div class="headertitle"><div class="title">**Basic Concept**  
</div></div></div>Previously Widgets where rather self-contained blocks of functionality. For example a needle widget would receive an input value (e.g. Speed) map it to a rotation angle and apply this rotation to a node.

<div class="contents" id="bkmrk-"><div class="contents"><div class="textblock"><div drawio-diagram="2353"><img src="https://doc316en.candera.eu/uploads/images/drawio/2023-02/drawing-7-1677206395.png" alt=""/></div>

</div></div></div>It would be possible to recreate this exact functionality as a behavior though the decision at [Candera](http://dev.doc.cgistudio.at/APILINK/namespace_candera.html "[DataBinding_RefTypeSample]") GmbH was to have multiple smaller behaviors which each implement only a small bit of functionality. Then combine these to achieve the desired results.

In the above sample this would result in a Value-Behavior which receives the value, a Map-Behavior which maps it to an angle and a Rotation-Behavior which applies the angle as a rotation on the node.

<div class="contents" id="bkmrk--0"><div class="contents"><div class="textblock"><div drawio-diagram="2354"><img src="https://doc316en.candera.eu/uploads/images/drawio/2023-02/drawing-7-1677206415.png" alt=""/></div>

</div></div></div>This approach has the advantage that it drastically improves the flexibility due to the modular design. For example if the rotation shouldn't happen instantly but slowly over time an interpolation behavior can be added.

<div class="contents" id="bkmrk--1"><div class="contents"><div class="textblock"><div drawio-diagram="2355"><img src="https://doc316en.candera.eu/uploads/images/drawio/2023-02/drawing-7-1677206427.png" alt=""/></div>

</div></div></div>If instead of rotating a needle, a pointer is just moved forward or back to indicate the value the Rotation-Behavior can be replaced with a Translation-Behavior.

<div class="contents" id="bkmrk--2"><div class="contents"><div class="textblock"><div drawio-diagram="2356"><img src="https://doc316en.candera.eu/uploads/images/drawio/2023-02/drawing-7-1677206442.png" alt=""/></div>

</div></div></div>All this can be achieved by simply recombining existing behaviors without the need to code new ones.

---

#### **Event Handler Behavior**

When an Event-Handler Behavior receives an event it will pass this event to a number of Condition-Behaviors. The Condition-Behaviors can then decide if this event is "accepted" or not. In case the event is accepted all attached Action-Behaviors will be executed.

##### How to create a new Condition-Behavior

To create a custom Condition-Behavior a new Behavior derived from Candera::ConditionBehavior must be created.

In the OnEvent() method an EvaluateConditionEvent will be received which allows to get the original event via the GetTriggerEvent() method. Further the dispatchResult will be of the type ConditionEvaluationResult. To accept the event the Match() method of the result must be called.

```
... 
void ClickConditionBehavior::OnEvent(const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_feat_std_1_1_event.html" title="Event serves as a base class for user derived events.">FeatStd::Event</a>& event, Candera::EventDispatchResult& dispatchResult) 
{     
    const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_evaluate_condition_event.html" title="The ConditionBehavior is referenced by an TriggerBehavior. ConditionBehavior and ActionBehavior are b...">Candera::EvaluateConditionEvent</a>* conditionBehaviorEvaluationEvent = Candera::Dynamic_Cast<const Candera::EvaluateConditionEvent*>(&event); 
 
    if (0 != conditionBehaviorEvaluationEvent) {         
        const ClickEvent* clickEvent =                
              Candera::Dynamic_Cast<const ClickEvent*>(&(conditionBehaviorEvaluationEvent-><a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_evaluate_condition_event.html#a189ee80c106180afad63fad526cc456b">GetTriggerEvent</a>())); 
 
        if (0 != clickEvent) {             
            if (clickEvent->GetClickCount() == GetClickCount()) {                 
                Candera::ConditionEvaluationResult* conditionEvaluationResult = Candera::Dynamic_Cast<Candera::ConditionEvaluationResult*>(&dispatchResult); 
 
                if (0 != conditionEvaluationResult) {                     
                    conditionEvaluationResult->Match();                 
                }             
             }         
        }     
    } 
} 
...
```

##### How to create a new Action Behavior

To create a custom Action-Behavior a new Behavior derived from [Candera::ActionBehavior](http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_action_behavior.html "The Action Behavior is part of the Event Handling with Behaviors pattern. It follows the ECA (Event-C...") must be created.

In the OnEvent() method an InvokeActionEvent will be received which indicates that the action should be executed.

```
... 
void ChangeValueActionBehavior::OnEvent(const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_feat_std_1_1_event.html" title="Event serves as a base class for user derived events.">FeatStd::Event</a>& event, Candera::EventDispatchResult& dispatchResult) 
{     
    FEATSTD_UNUSED(dispatchResult);     
    const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_invoke_action_event.html" title="Event to invoke an action. An input event is processed by a TriggerBehavior, which evaluates a condit...">Candera::InvokeActionEvent</a>* invokeActionEvent = Candera::Dynamic_Cast<const Candera::InvokeActionEvent*>(&event); 
 
    if (0 != invokeActionEvent) {         
        // Do something     
    } 
} 
... 
```

<div class="header" id="bkmrk-back-to-the-menu-0"><div class="headertitle"><div class="title align-left">---

</div></div></div>#### **How to handle Touch-Events**

To create a Behavior which reacts on Touch interaction a new Behavior derived from CgiStudioControl:: TouchableBehavior must be created. This class registers to the TouchSession and processes the incoming TouchSession-Events to perform a hit detection. If a hit is detected it is possible to react to Touch-Event in the behavior.

From the event the Touch-Info can be retrieved which contains important information about the Touch-State (Down, Move, Up), Pointer-Id (Multi-Touch), Source-Id (Multi-Display) and Touch-Coordinates.

```
...         
    virtual void OnEvent(const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_feat_std_1_1_event.html" title="Event serves as a base class for user derived events.">FeatStd::Event</a>& event, Candera::EventDispatchResult& dispatchResult)         
    {             
        const Candera::TouchEvent* touchEvent = Candera::Dynamic_Cast<const Candera::TouchEvent*>(&event); 
 
        if (touchEvent != 0) {                 
            switch (touchEvent->GetTouchInfo().m_state) {                     
                case <a class="code" href="http://dev.doc.cgistudio.at/APILINK/struct_candera_1_1_touch_info.html#a0115203900e842855ca9c7dd69107721a10cbf1c0a6ea47eaef08b88eadd88607">Candera::TouchInfo::Down</a>:                         
                    //OnBeginDrag(event.GetTouchInfo().m_x, event.GetTouchInfo().m_y);                         
                    break;                     
                case <a class="code" href="http://dev.doc.cgistudio.at/APILINK/struct_candera_1_1_touch_info.html#a0115203900e842855ca9c7dd69107721a08abf72a0e7c5d81cfaf58382e1df658">Candera::TouchInfo::Move</a>:                         
                    //OnDrag(event.GetTouchInfo().m_x, event.GetTouchInfo().m_y);                         
                    break;                     
                case <a class="code" href="http://dev.doc.cgistudio.at/APILINK/struct_candera_1_1_touch_info.html#a0115203900e842855ca9c7dd69107721a5584e1acc88c0a4386c327abf73cb4cd">Candera::TouchInfo::Up</a>:                         
                    //OnEndDrag(event.GetTouchInfo().m_x, event.GetTouchInfo().m_y);                         
                    break;                     
                default: break;                 
            }             
        } 
        else {                 
            Base::OnEvent(event, dispatchResult);             
        }         
    } 
...
```

##### Manual Touch handling

If a more customized processing of Touch-Events is required, instead of deriving from CgiStudioControl:: TouchableBehavior it is also possible to manually implement Touch-Handling. First the behavior must be marked as Touchable by implementing the "virtual bool IsTouchable() const" method or simply adding the following macro.

```
... 
CGI_BEHAVIOR_IS_TOUCHABLE() 
...
```

Next the Behavior must be registered/unregistered to the Touch-Session. This allows receiving TouchSession-Events.

```
...     
void TouchableBehavior::Register()     
{         
    Deregister();         
    Candera::TouchSession::GetInstance().Register(GetTouchable());         
    m_touchSession = &Candera::TouchSession::GetInstance();    
} 
 
void TouchableBehavior::Deregister()     
{         
    if (0 != m_touchSession) {             
        m_touchSession->Deregister(GetTouchable());             
        m_touchSession = 0;         
    }     
} 
...
```

The basic touch handling (object hit detection) must be manually implemented. This can be a bit more complicated but related code can be found in the TouchBehavior::OnEvent which can be used as basis for a custom implementation.

```
...     
    void TouchableBehavior::OnEvent(const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_feat_std_1_1_event.html" title="Event serves as a base class for user derived events.">FeatStd::Event</a>& event, Candera::EventDispatchResult& dispatchResult)
    {         
        if (!TouchSessionEventHandler::Handle(*this, event, dispatchResult)) { 
...             
            Base::OnEvent(event, dispatchResult);         
        }     
    } 
...
```

And the TouchSessionEventHandlerImpl::OnTouchSessionEvent.

```
...         
    void OnTouchSessionEvent(const Candera::TouchSessionEvent& event, Candera::TouchSessionEventDispatchResult& dispatchResult)         
    {             
        if (m_intersectionTest) {                 
            if (m_behavior.GetNode().IsEffectiveRenderingEnabled()) {                     
                <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view.html">Courier::View</a>* view = m_behavior.<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view.html#a873e33496b823c37e043688906db66ae" title="Returns the parent view.">GetParentView</a>();                     
                if (0 != view) {                         
                    const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_abstract_node_pointer.html" title="The class AbstractCameraPointer is an wrapper class to abstract 2D and 3D camera nodes.">Candera::AbstractNodePointer</a>& abstractNode = m_alternativeNode.<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_abstract_node_pointer_base.html#aa1bbbae49167cb862bdd4fbaadc3c18f">IsValid</a>() ? m_alternativeNode : m_behavior.GetNode();
                    const <a class="code" href="http://dev.doc.cgistudio.at/APILINK/struct_candera_1_1_touch_info.html" title="Description.">Candera::TouchInfo</a>& touchInfo = event.GetTouchInfo(); 
#ifdef CANDERA_2D_ENABLED
                    <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view_scene2_d.html">Courier::ViewScene2D</a>* viewScene2D = view->ToViewScene2D();                         
                    if (0 != viewScene2D) {                             
                        <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_node2_d.html" title="The class Node2D is an abstract base class for all 2D scene graph nodes.">Candera::Node2D</a>* node2D = abstractNode.<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_abstract_node_pointer_base.html#a332cbbcd777c748145418b8ff6911e4f">ToNode2D</a>();                             
                        if (0 != node2D) {                                 
                            Courier::ViewScene2D::CameraPtrVector& cameras = viewScene2D->GetCameraPtrVector(); 
                            for (FeatStd::SizeType i = 0; i < cameras.Size(); ++i) {
                                <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_vector2.html" title="The default Vector2 class.">Candera::Vector2</a> touchPosition(FeatStd::Float(touchInfo.m_x), FeatStd::Float(touchInfo.m_y));
                                if ((0 != cameras[i]) && node2D-><a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_node2_d.html#a2bc3ebd04baf379858acd754f97b3354">IsPickIntersectingBoundingRectangle</a>(*cameras[i], touchPosition)) {
                                     dispatchResult.SetTouched(true);
                                     dispatchResult.SetTouchUsage(m_touchUsage);                                         
                                     return;                                     
                                }                                 
                            }                             
                        }                         
                 } 
#endif 
#ifdef CANDERA_3D_ENABLED                         
                      <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view_scene3_d.html">Courier::ViewScene3D</a>* viewScene3D = view->ToViewScene3D();                         
                      if (0 != viewScene3D) {                             
                          <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_node.html" title="The class Node is an abstract base class for all scene graph nodes. Each Node defines a local coordin...">Candera::Node</a>* node = abstractNode.<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_abstract_node_pointer_base.html#a2da309042e58ef8e12f580c6533050f9">ToNode</a>();                             
                          if (0 != node) {                                 
                              Courier::ViewScene3D::CameraPtrVector& cameras = viewScene3D->GetCameraPtrVector(); 
                              for (FeatStd::SizeType i = 0; i < cameras.Size(); ++i) { 
                                   <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_camera.html" title="A Camera provides Modelview and Projection matrices. Camera is a Transformable.* The eye point is set...">Candera::Camera</a>* camera = cameras[i];                                     
                                   FeatStd::Float distance = Candera::Math::MaxFloat();
                                   if ((0 != camera) && camera-><a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_node.html#aedd4032a1ace92b9c2c7a97a9876ebf7">IsRenderingEnabled</a>() && node-><a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_candera_1_1_node.html#a0e1a8d24555a67b3cddf6a2ceef94481">IsPickIntersectingGeometry</a>(*camera, static_cast<FeatStd::Int>(touchInfo.m_x), 
                                                                                        static_cast<FeatStd::Int>(touchInfo.m_y), distance)) { 
                                        dispatchResult.SetTouched(true);                                         
                                        dispatchResult.SetTouchUsage(m_touchUsage);                                         
                                        return;
                                   }                                 
                              }                             
                          }                         
                      } 
#endif                     
                 }                 
             }             
         }             
         else {                 
             dispatchResult.SetTouched(true);                 
             dispatchResult.SetTouchUsage(m_touchUsage);             
         }         
     } 
... 
```

---

#### **How to handle View-Activation-Events**

View-Activation-Events are events send by the View to indicate if it has been activated or deactivated. To react to these events the Behavior must register at the View as an Event-Listener.

```
... 
EventListenerAdapter m_eventListenerAdapter; 
...
```

```
...     
    CustomBehavior::CustomBehavior()     
    {         
        m_eventListenerAdapter.SetBehavior(this);         
        <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view.html#a18dd6075cdc9de203f4b720595c58b8b">Courier::View::GetEventSource</a>().<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_feat_std_1_1_event_source.html#a82512678c455da0bfcc928d0f24b357b">AddEventListener</a>(&m_eventListenerAdapter);     
    } 
 
    CustomBehavior::~CustomBehavior ()     
    {         
        <a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view.html#a18dd6075cdc9de203f4b720595c58b8b">Courier::View::GetEventSource</a>().<a class="code" href="http://dev.doc.cgistudio.at/APILINK/class_feat_std_1_1_event_source.html#a92a06e13517c1dc371fd13a0f0ba5739">RemoveEventListener</a>(&m_eventListenerAdapter);         
        m_eventListenerAdapter.SetBehavior(0);     
    } 
...
```

It is now possible to receive as [Courier::ViewActivationEvent](http://dev.doc.cgistudio.at/APILINK/class_courier_1_1_view_activation_event.html) via the OnEvent() method.

---

####   