RTL support of FlexContainer
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / flex-container / flex-container-impl.cpp
old mode 100644 (file)
new mode 100755 (executable)
index 323a2cd..e1849bf
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,7 +22,8 @@
 #include <sstream>
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/object/type-registry.h>
-#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/scripting/scripting.h>
 #include <dali/public-api/size-negotiation/relayout-container.h>
 #include <dali/integration-api/debug.h>
@@ -31,20 +32,6 @@ using namespace Dali;
 
 namespace
 {
-/*
- * Custom properties for how to lay out the actor.
- *
- * When an actor is add to the flex container, the following custom properties of the actor
- * are checked to decide how to lay out the actor inside the flex container.
- *
- * These non-animatable properties should be registered to the child which would be added
- * to the flex container, and once added their values can not be changed.
- */
-const char * const FLEX_PROPERTY_NAME("flex");
-const char * const ALIGN_SELF_PROPERTY_NAME("alignSelf");
-const char * const FLEX_PADDING_PROPERTY_NAME("flexPadding");
-const char * const FLEX_BORDER_PROPERTY_NAME("flexBorder");
-const char * const FLEX_MARGIN_PROPERTY_NAME("flexMargin");
 
 #if defined(DEBUG_ENABLED)
 // debugging support, very useful when new features are added or bugs are hunted down
@@ -95,12 +82,15 @@ BaseHandle Create()
 // Setup properties, signals and actions using the type-registry.
 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
 
-DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "contentDirection",   INTEGER, CONTENT_DIRECTION )
-DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexDirection",      INTEGER, FLEX_DIRECTION    )
-DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "flexWrap",           INTEGER, FLEX_WRAP         )
-DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "justifyContent",     INTEGER, JUSTIFY_CONTENT   )
-DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignItems",         INTEGER, ALIGN_ITEMS       )
-DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer, "alignContent",       INTEGER, ALIGN_CONTENT     )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "contentDirection",  INTEGER,  CONTENT_DIRECTION )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "flexDirection",     INTEGER,  FLEX_DIRECTION    )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "flexWrap",          INTEGER,  FLEX_WRAP         )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "justifyContent",    INTEGER,  JUSTIFY_CONTENT   )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "alignItems",        INTEGER,  ALIGN_ITEMS       )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "alignContent",      INTEGER,  ALIGN_CONTENT     )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "flex",              FLOAT,    FLEX              )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "alignSelf",         INTEGER,  ALIGN_SELF        )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "flexMargin",        VECTOR4,  FLEX_MARGIN       )
 
 DALI_TYPE_REGISTRATION_END()
 
@@ -186,7 +176,6 @@ bool IsNodeDirty( void *itemNodes )
   // style properties are changed. So should always return true here.
   return true;
 }
-
 } // Unnamed namespace
 
 Toolkit::FlexContainer FlexContainer::New()
@@ -216,12 +205,42 @@ FlexContainer::~FlexContainer()
   mChildrenNodes.clear();
 }
 
-void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection )
+void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection)
 {
   if( mContentDirection != contentDirection )
   {
-    mContentDirection = contentDirection;
-    mRootNode.node->style.direction = static_cast<css_direction_t>( mContentDirection );
+    Dali::CustomActor ownerActor(GetOwner());
+
+    if( Toolkit::FlexContainer::INHERIT != contentDirection )
+    {
+      mContentDirection = contentDirection;
+
+      ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false );
+
+      if( Toolkit::FlexContainer::LTR == contentDirection )
+      {
+        ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
+      }
+      else
+      {
+        ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
+      }
+    }
+    else
+    {
+      ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true );
+
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetParent().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+
+      if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+      {
+        mContentDirection = Toolkit::FlexContainer::RTL;
+      }
+      else
+      {
+        mContentDirection = Toolkit::FlexContainer::LTR;
+      }
+    }
 
     RelayoutRequest();
   }
@@ -476,12 +495,6 @@ Property::Value FlexContainer::GetProperty( BaseObject* object, Property::Index
 
 void FlexContainer::OnChildAdd( Actor& child )
 {
-  Control::OnChildAdd( child );
-
-  // Anchor actor to top left of the container
-  child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-  child.SetParentOrigin( ParentOrigin::TOP_LEFT );
-
   // Create a new node for the child.
   FlexItemNode childNode;
   childNode.actor = child;
@@ -489,6 +502,8 @@ void FlexContainer::OnChildAdd( Actor& child )
   childNode.node->get_child = GetChildNodeAtIndex;
   childNode.node->is_dirty = IsNodeDirty;
   mChildrenNodes.push_back(childNode);
+
+  Control::OnChildAdd( child );
 }
 
 void FlexContainer::OnChildRemove( Actor& child )
@@ -516,6 +531,13 @@ void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& containe
     Actor child = mChildrenNodes[i].actor.GetHandle();
     if( child )
     {
+      // Anchor actor to top left of the container
+      if( child.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
+      {
+        child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      }
+      child.SetParentOrigin( ParentOrigin::TOP_LEFT );
+
       float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
       float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
 
@@ -538,13 +560,18 @@ void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& containe
     Actor child = mChildrenNodes[i].actor.GetHandle();
     if( child )
     {
-      if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
-      {
-        child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
-      }
-      if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
+      if( child.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
       {
-        child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
+        // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
+
+        if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
+        {
+          child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
+        }
+        if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
+        {
+          child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
+        }
       }
 
       container.Add( child, Vector2(mChildrenNodes[i].node->layout.dimensions[CSS_WIDTH], mChildrenNodes[i].node->layout.dimensions[CSS_HEIGHT] ) );
@@ -568,11 +595,33 @@ void FlexContainer::OnSizeSet( const Vector3& size )
 
     RelayoutRequest();
   }
+
+  Control::OnSizeSet( size );
 }
 
-void FlexContainer::OnSizeAnimation( Animation& animation, const Vector3& targetSize )
+void FlexContainer::OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
 {
-  // @todo Animate the children to their target size and position
+  Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
+  Toolkit::FlexContainer::ContentDirection direction;
+
+  if( type == Dali::LayoutDirection::RIGHT_TO_LEFT )
+  {
+    direction = Toolkit::FlexContainer::RTL;
+  }
+  else
+  {
+    direction = Toolkit::FlexContainer::LTR;
+  }
+
+  Toolkit::Internal::FlexContainer &flexContainerImpl = GetImpl( flexContainer );
+
+  if( flexContainerImpl.mContentDirection != direction )
+  {
+    Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
+    flexContainerImpl.mContentDirection = direction;
+
+    flexContainerImpl.RelayoutRequest();
+  }
 }
 
 void FlexContainer::ComputeLayout()
@@ -607,18 +656,19 @@ void FlexContainer::ComputeLayout()
       childNode->style.maxDimensions[CSS_WIDTH] = childActor.GetMaximumSize().x;
       childNode->style.maxDimensions[CSS_HEIGHT] = childActor.GetMaximumSize().y;
 
-      // Test custom properties on the child
-      if( childActor.GetPropertyIndex( FLEX_PROPERTY_NAME ) != Property::INVALID_INDEX )
+      // Check child properties on the child for how to layout it.
+      // These properties should be dynamically registered to the child which
+      // would be added to FlexContainer.
+
+      if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
       {
-        childNode->style.flex = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_PROPERTY_NAME) ).Get<float>();
+        childNode->style.flex = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>();
       }
 
-      Property::Index alignSelfPropertyIndex = childActor.GetPropertyIndex( ALIGN_SELF_PROPERTY_NAME );
-      if( alignSelfPropertyIndex != Property::INVALID_INDEX )
+      Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
+      if( childActor.GetPropertyType( Toolkit::FlexContainer::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
       {
-        Property::Value alignSelfPropertyValue = childActor.GetProperty( alignSelfPropertyIndex );
-
-        Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
+        Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
         if( alignSelfPropertyValue.GetType() == Property::INTEGER )
         {
           alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
@@ -631,30 +681,12 @@ void FlexContainer::ComputeLayout()
                                                                           ALIGN_SELF_STRING_TABLE_COUNT,
                                                                           alignSelf );
         }
-        childNode->style.align_self = static_cast<css_align_t>(alignSelf);
-      }
-
-      if( childActor.GetPropertyIndex( FLEX_PADDING_PROPERTY_NAME ) != Property::INVALID_INDEX )
-      {
-        Vector4 flexPadding = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_PADDING_PROPERTY_NAME) ).Get<Vector4>();
-        childNode->style.padding[CSS_LEFT] = flexPadding.x;
-        childNode->style.padding[CSS_TOP] = flexPadding.y;
-        childNode->style.padding[CSS_RIGHT] = flexPadding.z;
-        childNode->style.padding[CSS_BOTTOM] = flexPadding.w;
-      }
-
-      if( childActor.GetPropertyIndex( FLEX_BORDER_PROPERTY_NAME ) != Property::INVALID_INDEX )
-      {
-        Vector4 flexBorder = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_BORDER_PROPERTY_NAME) ).Get<Vector4>();
-        childNode->style.border[CSS_LEFT] = flexBorder.x;
-        childNode->style.border[CSS_TOP] = flexBorder.y;
-        childNode->style.border[CSS_RIGHT] = flexBorder.z;
-        childNode->style.border[CSS_BOTTOM] = flexBorder.w;
       }
+      childNode->style.align_self = static_cast<css_align_t>(alignSelf);
 
-      if( childActor.GetPropertyIndex( FLEX_MARGIN_PROPERTY_NAME ) != Property::INVALID_INDEX )
+      if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
       {
-        Vector4 flexMargin = childActor.GetProperty( childActor.GetPropertyIndex(FLEX_MARGIN_PROPERTY_NAME) ).Get<Vector4>();
+        Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
         childNode->style.margin[CSS_LEFT] = flexMargin.x;
         childNode->style.margin[CSS_TOP] = flexMargin.y;
         childNode->style.margin[CSS_RIGHT] = flexMargin.z;
@@ -663,7 +695,29 @@ void FlexContainer::ComputeLayout()
     }
 
     // Calculate the layout
-    layoutNode( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, mRootNode.node->style.direction );
+    css_direction_t nodeLayoutDirection = CSS_DIRECTION_INHERIT;
+    switch( mContentDirection )
+    {
+    case Dali::Toolkit::FlexContainer::LTR:
+    {
+      nodeLayoutDirection = CSS_DIRECTION_LTR;
+      break;
+    }
+
+    case Dali::Toolkit::FlexContainer::RTL:
+    {
+      nodeLayoutDirection = CSS_DIRECTION_RTL;
+      break;
+    }
+
+    case Dali::Toolkit::FlexContainer::INHERIT:
+    {
+      nodeLayoutDirection = CSS_DIRECTION_INHERIT;
+      break;
+    }
+    }
+
+    layoutNode( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, nodeLayoutDirection);
   }
 }
 
@@ -758,6 +812,10 @@ Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, To
             } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
             break;
           }
+          default:
+          {
+            break;
+          }
         }
 
         if( nextFocusedActorIndex != currentFocusedActorIndex )
@@ -782,7 +840,7 @@ Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, To
 }
 
 FlexContainer::FlexContainer()
-: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
   mContentDirection( Toolkit::FlexContainer::INHERIT ),
   mFlexDirection( Toolkit::FlexContainer::COLUMN ),
   mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
@@ -797,6 +855,8 @@ void FlexContainer::OnInitialize()
 {
   // Initialize the node for the flex container itself
   Dali::Actor self = Self();
+  self.LayoutDirectionChangedSignal().Connect( this, &FlexContainer::OnLayoutDirectionChanged );
+
   mRootNode.actor = self;
   mRootNode.node = new_css_node();
   mRootNode.node->context = &mChildrenNodes;