Yoga API wrapped by FlexLayout 68/201568/43
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Fri, 15 Mar 2019 17:20:13 +0000 (17:20 +0000)
committeragnelo vaz <agnelo.vaz@samsung.com>
Tue, 4 Jun 2019 15:58:18 +0000 (16:58 +0100)
Change-Id: If8e80a7e2857d2ea5e8b1b96fb4bb30a7a1279d8

automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-FlexNode.cpp [new file with mode: 0755]
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/layouting/flex-node.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/flex-node.h [new file with mode: 0644]
dali-toolkit/internal/controls/flex-container/flex-container-impl.h

index 36f4850..993601c 100755 (executable)
@@ -18,6 +18,7 @@ SET(TC_SOURCES
   utc-Dali-CubeTransitionEffect.cpp
   utc-Dali-EffectsView.cpp
   utc-Dali-FlexContainer.cpp
+  utc-Dali-FlexNode.cpp
   utc-Dali-GaussianBlurView.cpp
   utc-Dali-ImageView.cpp
   utc-Dali-ImageVisual.cpp
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-FlexNode.cpp b/automated-tests/src/dali-toolkit/utc-Dali-FlexNode.cpp
new file mode 100755 (executable)
index 0000000..3d54ae2
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali-toolkit/devel-api/layouting/flex-node.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_flexNodeContainer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_flexNodeContainer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const Flex::SizeTuple ITEM_SIZE = Flex::SizeTuple{ 10.0f, 10.0f };
+const Flex::SizeTuple ITEM_SIZE_CALLBACK_TEST = Flex::SizeTuple{ 15.0f, 15.0f };
+
+Flex::SizeTuple MeasureChild( Actor child, float width, int measureModeWidth, float height, int measureModeHeight)
+{
+  Flex::SizeTuple childSize = ITEM_SIZE;
+  if (child.GetName() == "callbackTest")
+  {
+    childSize = ITEM_SIZE_CALLBACK_TEST;
+  }
+  tet_printf(" MeasureChild test callback executed (%f,%f)\n", childSize.width, childSize.height );
+  return childSize;
+}
+
+}
+
+int UtcDaliToolkitFlexNodeConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeNewP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeAddChildrenRowP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeAddChildrenRowP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements as a Row
+  flexNode->SetFlexDirection(Flex::FlexDirection::ROW);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexDirection(), (int)Flex::FlexDirection::ROW, TEST_LOCATION );
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( ITEM_SIZE.width, 0.0f, ITEM_SIZE.width * 2, ITEM_SIZE.height ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeAddChildrenColumnP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeAddChildrenColumnP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection(Flex::FlexDirection::COLUMN);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE.height, ITEM_SIZE.width, ITEM_SIZE.height *2 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliToolkitFlexNodeAddChildrenColumnJustify(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeAddChildrenColumnJustify");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection(Flex::FlexDirection::COLUMN);
+
+  tet_infoline("Justify to the Start, align to start");
+  flexNode->SetFlexJustification(Flex::Justification::FLEX_START);
+  flexNode->SetFlexItemsAlignment( Flex::Alignment::FLEX_START );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexJustification(), (int)Flex::Justification::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexItemsAlignment(), (int)Flex::Alignment::FLEX_START, TEST_LOCATION );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  /*
+    ---------
+    |1      |
+    |2      |
+    |       |
+    |       |
+    |       |
+    ---------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE.height, ITEM_SIZE.width, ITEM_SIZE.height *2 ), TEST_LOCATION );
+
+  tet_infoline(" Justify to the End, items should now be displayed at the bottom");
+  flexNode->SetFlexJustification( Flex::Justification::FLEX_END );
+  flexNode->SetFlexItemsAlignment( Flex::Alignment::FLEX_START );
+
+  // Recalulate layout
+  flexNode->CalculateLayout(480, 800, false);
+
+  root = flexNode->GetNodeFrame(-1); // -1 is the root
+  actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  /*
+    ---------
+    |       |
+    |       |
+    |       |
+    |1      |
+    |2      |
+    ---------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, root.w - (ITEM_SIZE.height*2), ITEM_SIZE.width,  root.w - ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, root.w - ITEM_SIZE.height, ITEM_SIZE.width, root.w ), TEST_LOCATION );
+
+  tet_infoline(" Align to End, items should now be displayed at the bottom and the end");
+  flexNode->SetFlexJustification( Flex::Justification::FLEX_END );
+  flexNode->SetFlexItemsAlignment( Flex::Alignment::FLEX_END );
+  // Recalulate layout
+  flexNode->CalculateLayout(480, 800, false);
+
+  root = flexNode->GetNodeFrame(-1); // -1 is the root
+  actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  /*
+    ---------
+    |       |
+    |       |
+    |       |
+    |      1|
+    |      2|
+    ---------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( root.z - ITEM_SIZE.width, root.w - (ITEM_SIZE.height*2), root.z,  root.w - ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( root.z - ITEM_SIZE.width, root.w - ITEM_SIZE.height, root.z, root.w ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeSizingP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeSizingP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  DALI_TEST_EQUALS( flexNode->GetFlexWidth(), 480.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( flexNode->GetFlexHeight(), 800.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeWrapModeP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeWrapModeP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection( Flex::FlexDirection::ROW );
+  flexNode->SetFlexAlignment( Flex::Alignment::FLEX_START );
+  flexNode->SetFlexWrap( Flex::WrapType::NO_WRAP );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  Actor actor3 = Actor::New();
+  Actor actor4 = Actor::New();
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexJustification(), (int)Flex::Justification::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexItemsAlignment(), (int)Flex::Alignment::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexAlignment(), (int)Flex::Alignment::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexWrap(), (int)Flex::WrapType::NO_WRAP, TEST_LOCATION );
+
+  flexNode->AddChild( actor1, &MeasureChild, 0 );
+  flexNode->AddChild( actor2, &MeasureChild, 1 );
+  flexNode->AddChild( actor2, &MeasureChild, 2 );
+  flexNode->AddChild( actor2, &MeasureChild, 3 );
+
+  flexNode->CalculateLayout(30, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+  Vector4 actor3Frame = flexNode->GetNodeFrame(2); // 2 is first child
+  Vector4 actor4Frame = flexNode->GetNodeFrame(3); // 3 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+  tet_printf("Actor 3 frame(left:%f,top:%f,right:cdt%f,bottom:%f)\n", actor3Frame.x, actor3Frame.y, actor3Frame.z, actor3Frame.w);
+  tet_printf("Actor 4 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor4Frame.x, actor4Frame.y, actor4Frame.z, actor4Frame.w);
+
+  /*
+    -------
+    |1 2 3 4     |
+    |     |
+    |     |
+    |     |
+    |     |
+    -------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f,            0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( ITEM_SIZE.width, 0.0f, ITEM_SIZE.width*2, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3Frame, Vector4( ITEM_SIZE.width*2, 0.0f, ITEM_SIZE.width*3, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor4Frame, Vector4( ITEM_SIZE.width*3, 0.0f, ITEM_SIZE.width*4, ITEM_SIZE.height ), TEST_LOCATION );
+
+  flexNode->SetFlexWrap( Flex::WrapType::WRAP );
+
+  flexNode->CalculateLayout( 30, 800, false );
+  root = flexNode->GetNodeFrame(-1); // -1 is the root
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexWrap(), (int)Flex::WrapType::WRAP, TEST_LOCATION );
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+  actor3Frame = flexNode->GetNodeFrame(2); // 2 is first child
+  actor4Frame = flexNode->GetNodeFrame(3); // 3 is second child
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+  tet_printf("Actor 3 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor3Frame.x, actor3Frame.y, actor3Frame.z, actor3Frame.w);
+  tet_printf("Actor 4 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor4Frame.x, actor4Frame.y, actor4Frame.z, actor4Frame.w);
+
+  /*
+    -------
+    |1 2 3|     |
+    |4    |
+    |     |
+    |     |
+    |     |
+    -------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f,            0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( ITEM_SIZE.width, 0.0f, ITEM_SIZE.width*2, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3Frame, Vector4( ITEM_SIZE.width*2, 0.0f, ITEM_SIZE.width*3, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor4Frame, Vector4( 0.0,ITEM_SIZE.height, ITEM_SIZE.width, ITEM_SIZE.height*2 ), TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeRemoveChildP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeRemoveChildP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  actor1.SetName("Actor1");
+  actor2.SetName("Actor2");
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE.width, ITEM_SIZE.width, ITEM_SIZE.height*2 ), TEST_LOCATION );
+
+  flexNode->RemoveChild(actor1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  actor2Frame = flexNode->GetNodeFrame(0);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeRemoveAllChildrenP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeRemoveAllChildrenP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  actor1.SetName("Actor1");
+  actor2.SetName("Actor2");
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  flexNode->RemoveChild(actor1);
+  flexNode->RemoveChild(actor2);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1FrameRemoved = flexNode->GetNodeFrame(0);
+  Vector4 actor2FrameRemoved = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1FrameRemoved.x, actor1FrameRemoved.y, actor1FrameRemoved.z, actor1FrameRemoved.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2FrameRemoved.x, actor2FrameRemoved.y, actor2FrameRemoved.z, actor2FrameRemoved.w);
+
+  DALI_TEST_NOT_EQUALS( actor1Frame, actor1FrameRemoved, 0.1, TEST_LOCATION );
+  DALI_TEST_NOT_EQUALS( actor2Frame, actor2FrameRemoved, 0.1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodePaddingMarginP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodePaddingMarginP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+  flexNode->SetFlexDirection( Flex::FlexDirection::ROW );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  Extents padding( 5,5,5,5);
+  Extents margin( 5,5,5,5);
+
+  flexNode->SetPadding( padding );
+  flexNode->SetMargin( margin );
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  /*  p = padding
+  -----
+  |ppppp|
+  |p1 2p|
+  |p   p|
+  |ppppp|
+  -------
+  */
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 5.0f, 5.0f, ITEM_SIZE.width +5 , ITEM_SIZE.height + 5 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 5+ ITEM_SIZE.width, 5.0f, (ITEM_SIZE.width*2) +5, ITEM_SIZE.height +5 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeCallbackTestP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeCallbackTestP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection(Flex::FlexDirection::COLUMN);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+
+  actor1.SetName("callbackTest");
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, &MeasureChild, 0);
+  flexNode->AddChild(actor2, &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE_CALLBACK_TEST.width, ITEM_SIZE_CALLBACK_TEST.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE_CALLBACK_TEST.height, ITEM_SIZE.width, ITEM_SIZE_CALLBACK_TEST.height + ITEM_SIZE.height ), TEST_LOCATION );
+
+  END_TEST;
+}
index 7ae9e86..65403db 100755 (executable)
@@ -34,6 +34,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/image-loader/atlas-upload-observer.cpp \
   $(devel_api_src_dir)/image-loader/image-atlas.cpp \
   $(devel_api_src_dir)/image-loader/texture-manager.cpp \
+  $(devel_api_src_dir)/layouting/flex-node.cpp \
   $(devel_api_src_dir)/scripting/script.cpp \
   $(devel_api_src_dir)/styling/style-manager-devel.cpp \
   $(devel_api_src_dir)/text/bitmap-font.cpp \
@@ -79,6 +80,9 @@ devel_api_builder_header_files = \
 devel_api_effects_view_header_files = \
   $(devel_api_src_dir)/controls/effects-view/effects-view.h
 
+devel_api_layouting_header_files = \
+  $(devel_api_src_dir)/layouting/flex-node.h
+
 devel_api_magnifier_header_files = \
   $(devel_api_src_dir)/controls/magnifier/magnifier.h
 
diff --git a/dali-toolkit/devel-api/layouting/flex-node.cpp b/dali-toolkit/devel-api/layouting/flex-node.cpp
new file mode 100644 (file)
index 0000000..c2157f1
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//CLASS HEADER
+#include "flex-node.h"
+
+//EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/weak-handle.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/third-party/yoga/Yoga.h>
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_FLEX" );
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Flex
+{
+
+namespace
+{
+// Common callback function that is registered when AddChild is called.
+// Calls MeasureNode which in turns calls the actual callback passed in AddChild not the common callback.
+YGSize MeasureChild(YGNodeRef child, float width, YGMeasureMode measureModeWidth, float height, YGMeasureMode measureModeHeight)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "MeasureChild\n" );
+  // Get the Node from the YGNodeRef
+  Toolkit::Flex::Node* childNode =  static_cast<Toolkit::Flex::Node*>(YGNodeGetContext(child));
+
+  YGSize childSize = YGSize{.width = 1, .height = 1};  // Initialise variable.
+
+  DALI_ASSERT_DEBUG( childNode );
+
+  // Call measure function assigned to this Node
+  Toolkit::Flex::SizeTuple nodeSize = childNode->MeasureNode( width, measureModeWidth, height, measureModeHeight );
+  childSize.width = nodeSize.width;
+  childSize.height = nodeSize.height;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "MeasureChild, childNode valid %f,%f\n", childSize.width, childSize.height );
+
+  return childSize;
+}
+
+} // unamed namespace
+
+struct Node;
+
+using NodePtr = std::unique_ptr<Node>;
+
+using  FlexNodeVector = std::vector< NodePtr>;
+
+struct Node::Impl
+{
+  YGNodeRef mYogaNode;
+  MeasureCallback mMeasureCallback;
+  WeakHandle< Dali::Actor > mActor;
+  FlexNodeVector mChildNodes;
+};
+
+Node::Node() : mImpl( new Impl )
+{
+  mImpl->mYogaNode = YGNodeNew();
+  YGNodeSetContext( mImpl->mYogaNode, this );
+  mImpl->mMeasureCallback = NULL;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Node()  Context [%p] set to mYogaNode[%p]\n", this, mImpl->mYogaNode );
+
+  // Set default style
+  YGNodeStyleSetFlexDirection( mImpl->mYogaNode, YGFlexDirectionColumn );
+  YGNodeStyleSetFlexWrap( mImpl->mYogaNode, YGWrapNoWrap );
+  YGNodeStyleSetJustifyContent( mImpl->mYogaNode, YGJustifyFlexStart );
+  YGNodeStyleSetAlignContent( mImpl->mYogaNode, YGAlignFlexStart );
+  YGNodeStyleSetAlignItems( mImpl->mYogaNode, YGAlignFlexStart );
+}
+
+Node::~Node()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destructor() >> \n");
+  if( mImpl->mYogaNode )
+  {
+    YGNodeFreeRecursive( mImpl->mYogaNode );
+    mImpl->mYogaNode = nullptr;
+  }
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destructor() <<\n");
+}
+
+void Node::AddChild( Actor child, MeasureCallback measureFunction, int index )
+{
+  if( child )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddChild[%s] to node[%p] at index:%d\n", child.GetName().c_str(), mImpl->mYogaNode, index );
+
+    NodePtr childNode( new Node() );
+
+    // Store measure function passed in so can call it when the MeasureChild function is called.
+    childNode->mImpl->mMeasureCallback = measureFunction;
+
+    childNode->mImpl->mActor = child;
+    Vector2 minumumSize = child.GetMinimumSize();
+    Vector2 maximumSize = child.GetMaximumSize();
+    YGNodeStyleSetMaxWidth( childNode->mImpl->mYogaNode, maximumSize.width );
+    YGNodeStyleSetMaxHeight( childNode->mImpl->mYogaNode, maximumSize.height );
+    YGNodeStyleSetMinWidth( childNode->mImpl->mYogaNode, minumumSize.width );
+    YGNodeStyleSetMinHeight( childNode->mImpl->mYogaNode, minumumSize.height );
+
+    YGNodeSetMeasureFunc( childNode->mImpl->mYogaNode, &MeasureChild );
+
+    YGNodeInsertChild( mImpl->mYogaNode, childNode->mImpl->mYogaNode, index );
+
+    mImpl->mChildNodes.emplace_back( std::move(childNode) );
+  }
+}
+
+void Node::RemoveChild( Actor child )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RemoveChild child:[%s] from internal nodeCount[%d] childCount[%d]\n", child.GetName().c_str(), YGNodeGetChildCount( mImpl->mYogaNode ), mImpl->mChildNodes.size()  );
+
+  auto iterator = std::find_if( mImpl->mChildNodes.begin(),mImpl->mChildNodes.end(),
+                                [&child]( NodePtr& childNode ){ return childNode->mImpl->mActor.GetHandle() == child;});
+
+  if( iterator != mImpl->mChildNodes.end() )
+  {
+      YGNodeRemoveChild( mImpl->mYogaNode, (*iterator)->mImpl->mYogaNode );
+      mImpl->mChildNodes.erase(iterator);
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RemoveChild internal nodeCount[%d] childCount[%d]\n", YGNodeGetChildCount( mImpl->mYogaNode ), mImpl->mChildNodes.size()  );
+}
+
+SizeTuple Node::MeasureNode( float width, int widthMode, float height, int heightMode)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode\n" );
+
+  // Execute callback registered with AddChild
+  Toolkit::Flex::SizeTuple nodeSize{8,8}; // Default size set to 8,8 to aid bug detection.
+  if( mImpl->mMeasureCallback && mImpl->mActor.GetHandle() )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode MeasureCallback executing on %s\n", mImpl->mActor.GetHandle().GetName().c_str() );
+    nodeSize = mImpl->mMeasureCallback( mImpl->mActor.GetHandle(), width, widthMode, height, heightMode );
+  }
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode nodeSize width:%f height:%f\n", nodeSize.width, nodeSize.height );
+  return nodeSize;
+}
+
+void Node::CalculateLayout(float availableWidth, float availableHeight, bool isRTL)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "CalculateLayout availableSize(%f,%f)\n", availableWidth, availableHeight );
+  YGNodeCalculateLayout( mImpl->mYogaNode, availableWidth, availableHeight, isRTL ? YGDirectionRTL : YGDirectionLTR );
+}
+
+Dali::Vector4 Node::GetNodeFrame( int index ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame[%d]\n", index );
+  YGNodeRef childNode = YGNodeGetChild( mImpl->mYogaNode, index );
+  Dali::Vector4 frame = Vector4::ZERO;
+  if(childNode)
+  {
+    frame.x = YGNodeLayoutGetLeft( childNode );
+    frame.y = YGNodeLayoutGetTop( childNode );
+    frame.z = frame.x + YGNodeLayoutGetWidth( childNode );
+    frame.w = frame.y + YGNodeLayoutGetHeight( childNode );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame Node index[%d] child ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n",
+                   index, childNode, frame.x , frame.y, frame.z, frame.w);
+  }
+  else
+  {
+    frame.x = YGNodeLayoutGetLeft( mImpl->mYogaNode );
+    frame.y = YGNodeLayoutGetTop( mImpl->mYogaNode );
+    frame.z = frame.x + YGNodeLayoutGetWidth( mImpl->mYogaNode );
+    frame.w = frame.y + YGNodeLayoutGetHeight( mImpl->mYogaNode );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame Root index[%d] root ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n",
+                   index, mImpl->mYogaNode, frame.x , frame.y, frame.z, frame.w);
+  }
+
+  return frame;
+}
+void Node::SetFlexDirection( Dali::Toolkit::Flex::FlexDirection flexDirection )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex direction[%d]\n", flexDirection );
+
+  YGNodeStyleSetFlexDirection( mImpl->mYogaNode, static_cast<YGFlexDirection>(flexDirection) );
+}
+
+Dali::Toolkit::Flex::FlexDirection Node::GetFlexDirection() const
+{
+  return static_cast<Dali::Toolkit::Flex::FlexDirection>(YGNodeStyleGetFlexDirection( mImpl->mYogaNode ));
+}
+
+void Node::SetFlexJustification( Dali::Toolkit::Flex::Justification flexJustification )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex justification[%d]\n", flexJustification )
+
+  YGNodeStyleSetJustifyContent( mImpl->mYogaNode, static_cast<YGJustify>(flexJustification) );
+}
+
+Dali::Toolkit::Flex::Justification Node::GetFlexJustification() const
+{
+  return static_cast<Dali::Toolkit::Flex::Justification>(YGNodeStyleGetJustifyContent( mImpl->mYogaNode ));
+}
+
+Dali::Toolkit::Flex::WrapType Node::GetFlexWrap() const
+{
+  return static_cast<Dali::Toolkit::Flex::WrapType>(YGNodeStyleGetFlexWrap( mImpl->mYogaNode ));
+}
+
+void Node::SetFlexAlignment(Dali::Toolkit::Flex::Alignment flexAlignment )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex alignment[%d]\n", flexAlignment )
+
+  YGNodeStyleSetAlignContent( mImpl->mYogaNode , static_cast<YGAlign>(flexAlignment) );
+}
+
+Dali::Toolkit::Flex::Alignment Node::GetFlexAlignment() const
+{
+  return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignContent( mImpl->mYogaNode ));
+}
+
+void Node::SetFlexItemsAlignment(Dali::Toolkit::Flex::Alignment flexAlignment )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex items alignment[%d] on mYogaNode[%p]\n", flexAlignment, mImpl->mYogaNode )
+
+  YGNodeStyleSetAlignItems( mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment) );
+}
+
+Dali::Toolkit::Flex::Alignment Node::GetFlexItemsAlignment() const
+{
+  return static_cast<Dali::Toolkit::Flex::Alignment>( YGNodeStyleGetAlignItems( mImpl->mYogaNode ));
+}
+
+float Node::GetFlexWidth() const
+{
+  float flexWidth = YGNodeLayoutGetWidth( mImpl->mYogaNode );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] width[%f]\n", mImpl->mYogaNode, flexWidth)
+
+  return flexWidth;
+}
+
+float Node::GetFlexHeight() const
+{
+  float flexHeight = YGNodeLayoutGetHeight( mImpl->mYogaNode );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] height[%f]\n", mImpl->mYogaNode, flexHeight)
+
+  return flexHeight;
+}
+
+void Node::SetMargin( Extents margin )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex margin\n")
+
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeLeft, margin.start );
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeTop, margin.top );
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeRight, margin.end );
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeBottom, margin.bottom );
+}
+
+void Node::SetPadding( Extents padding )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set padding\n")
+
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeLeft, padding.start );
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeTop, padding.top );
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeRight, padding.end );
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeBottom, padding.bottom );
+}
+
+void Node::SetFlexWrap( Dali::Toolkit::Flex::WrapType wrapType )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex wrap[%d] on mYogaNode[%p]\n", wrapType, mImpl->mYogaNode )
+
+  YGNodeStyleSetFlexWrap( mImpl->mYogaNode, static_cast<YGWrap>(wrapType) );
+}
+
+} // Flex
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/flex-node.h b/dali-toolkit/devel-api/layouting/flex-node.h
new file mode 100644 (file)
index 0000000..034e555
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_FLEX_NODE_H
+#define DALI_TOOLKIT_LAYOUTING_FLEX_NODE_H
+
+/*
+ * Copyright (c) 2019 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <memory>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/actors/actor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Flex
+{
+
+class Node;
+
+/**
+ * @brief Enumeration for the direction of the main axis in the flex container. This determines
+ * the direction that flex items are laid out in the flex container.
+ */
+enum class FlexDirection
+{
+  COLUMN,                  ///< The flexible items are displayed vertically as a column
+  COLUMN_REVERSE,          ///< The flexible items are displayed vertically as a column, but in reverse order
+  ROW,                     ///< The flexible items are displayed horizontally as a row
+  ROW_REVERSE              ///< The flexible items are displayed horizontally as a row, but in reverse order
+};
+
+/**
+ * @brief Enumeration for the alignment of the flex items when the items do not use all available
+ * space on the main-axis.
+ */
+enum class Justification
+{
+  FLEX_START,              ///< Items are positioned at the beginning of the container
+  CENTER,                  ///< Items are positioned at the center of the container
+  FLEX_END,                ///< Items are positioned at the end of the container
+  SPACE_BETWEEN,           ///< Items are positioned with equal space between the items
+  SPACE_AROUND             ///< Items are positioned with equal space before, between, and after the items
+};
+
+/**
+ * @brief Enumeration for the wrap type of the flex container when there is not enough room for
+ * all the items on one flex line.
+ */
+enum class WrapType
+{
+  NO_WRAP,                 ///< Flex items laid out in single line (shrunk to fit the flex container along the main axis)
+  WRAP                     ///< Flex items laid out in multiple lines if needed
+};
+
+/**
+ * @brief Enumeration for the alignment of the flex items or lines when the items or lines do not
+ * use all the available space on the cross-axis.
+ */
+enum class Alignment
+{
+    AUTO,                  ///< Currently unsupported, placeholder for inheritance of parent alignment.
+
+    FLEX_START,            ///< At the beginning of the container
+    CENTER,                ///< At the center of the container
+    FLEX_END,              ///< At the end of the container
+    STRETCH                ///< Stretch to fit the container
+};
+
+
+/**
+ * Struct used for MeasureCallback
+ */
+struct SizeTuple
+{
+  SizeTuple( float x, float y ) : width( x ), height( y ){}
+
+  float width;
+  float height;
+};
+
+/**
+ * @brief Callback signature for child Actor measure callback.
+ * @note Actor, child Actor to measure
+ * @note float, available width for child
+ * @note int, width measure specifcation mode
+ * @note float, available height for child
+ * @note int, height measure specification mode
+ */
+using MeasureCallback = SizeTuple (*)( Dali::Actor, float , int , float , int );
+
+/**
+ * This class provides the API for calling into the Flex layout implementation.
+ */
+class DALI_TOOLKIT_API Node
+{
+public:
+  /**
+   * @brief Constructor.
+   */
+  Node();
+
+  /**
+   * @brief Destructor.
+   */
+  ~Node();
+
+  Node& operator=(Node&&) = default;
+  Node(Node&&) = default;
+  Node(const Node&) = delete;
+  Node& operator=(const Node&) = delete;
+
+  /**
+   * @brief Insert child into the FlexLayout at the given index.
+   * @param[in] child Actor to insert.
+   * @param[in] measureFunction for the child.
+   * @param[in] index to insert at.
+   */
+  void AddChild( Actor child, MeasureCallback measureFunction, int index );
+
+  /**
+   * @brief Remove child from the FlexLayout at the given index.
+   * @param[in] child child to be removed.
+   */
+  void RemoveChild( Actor child );
+
+  /**
+   * @brief Return the dimensions of the node.
+   * @param[in] width width specification
+   * @param[in] widthMode width specification mode
+   * @param[in] height height specification
+   * @param[in] heightMode height specification mode
+   * @return Size tuple representing the width and height of the node
+   */
+  SizeTuple MeasureNode( float width, int widthMode, float height, int heightMode );
+
+  /**
+   * @brief Perform the layout measure calculations.
+   * @param[in] availableWidth Amount of space available for layout, width.
+   * @param[in] availableHeight Amount of space available for layout, height.
+   * @param[in] isRTL Is the direction of the layout right to left.
+   */
+  void CalculateLayout( float availableWidth, float availableHeight, bool isRTL );
+
+  /**
+   * @brief Get the calculated width of the given node.
+   * @return the width of the node
+   */
+  float GetFlexWidth() const;
+
+  /**
+   * @brief Get the calculated height of the given node.
+   * @return the height of the node
+   */
+  float GetFlexHeight() const;
+
+  /**
+   * @brief Get frame coordinates of the node at the given index.
+   * @param[in] index of the child
+   * @return Frame structure left x, top y, right z, bottom w
+   */
+  Vector4 GetNodeFrame(int index ) const;
+
+  /**
+   * @brief Set the flex direction in the layout.
+   * The direction of the main-axis which determines the direction that flex items are laid out.
+   * @param[in] flexDirection The flex direction.
+   */
+  void SetFlexDirection( FlexDirection flexDirection );
+
+  /**
+   * @brief Get the flex direction in the layout.
+   * @return The flex direction.
+   */
+  FlexDirection GetFlexDirection() const;
+
+  /**
+   * @brief Set the justification in the layout.
+   * @param[in] flexJustification The flex justification.
+   */
+  void SetFlexJustification( Justification flexJustification );
+
+  /**
+   * @brief Get the flex justification in the layout.
+   * @return The flex justification.
+   */
+  Justification GetFlexJustification() const;
+
+  /**
+   * @brief Set the wrap in the layout.
+   * @param[in] flexWrap The flex wrap.
+   */
+  void SetFlexWrap(WrapType flexWrap );
+
+  /**
+   * @brief Get the flex wrap in the layout.
+   * @return The flex wrap.
+   */
+  WrapType GetFlexWrap() const;
+
+  /**
+   * @brief Set the alignment of the layout content.
+   * @param[in] flexAlignment The alignment of the content.
+   */
+  void SetFlexAlignment( Alignment flexAlignment );
+
+  /**
+   * @brief Get the alignment of the layout content.
+   * @return The flex content alignment.
+   */
+  Alignment GetFlexAlignment() const;
+
+  /**
+   * @brief Set the alignment of the layout items.
+   * @param[in] flexAlignment The alignment of the items.
+   */
+  void SetFlexItemsAlignment( Alignment flexAlignment );
+
+  /**
+   * @brief Get the alignment of the layout items.
+   * @return The flex items alignment.
+   */
+  Alignment GetFlexItemsAlignment() const;
+
+  /**
+   * @brief Set the margin.
+   * @param[in] margin The margin value.
+   */
+  void SetMargin( Extents margin );
+
+  /**
+   * @brief Set the padding.
+   * @param[in] padding The padding value.
+   */
+  void SetPadding( Extents padding );
+
+private:
+  struct Impl;
+  std::unique_ptr< Impl > mImpl;
+
+}; // Node
+
+
+} // namespace Flex
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_FLEX_NODE_H
index a06c8a9..a4cb269 100755 (executable)
@@ -36,7 +36,7 @@ namespace Internal
 {
 
 /**
- * FlexContainer is a custom control for laying out actors in a flexbox layout
+ * FlexContainer is a custom control for laying out actors in a Flexbox layout
  * @see Dali::Toolkit:FlexContainer for more details
  */
 class FlexContainer : public Control