Adding GridLayout 15/182515/18
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Mon, 25 Jun 2018 15:41:31 +0000 (16:41 +0100)
committerAgnelo Vaz <agnelo.vaz@samsung.com>
Wed, 8 Aug 2018 17:49:15 +0000 (18:49 +0100)
Change-Id: I2e23b7b2a396677167a88f6366a6b9ea6d0f617b

automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/utc-Dali-GridLayout.cpp [new file with mode: 0644]
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/layouting/grid.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/grid.h [new file with mode: 0644]
dali-toolkit/internal/file.list
dali-toolkit/internal/layouting/grid-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/grid-impl.h [new file with mode: 0644]
dali-toolkit/internal/layouting/grid-locations.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/grid-locations.h [new file with mode: 0644]

index 5852cfc..086f621 100755 (executable)
@@ -20,6 +20,7 @@ SET(TC_SOURCES
   utc-Dali-FlexContainer.cpp
   utc-Dali-FlexLayout.cpp
   utc-Dali-GaussianBlurView.cpp
+  utc-Dali-GridLayout.cpp
   utc-Dali-ImageView.cpp
   utc-Dali-ImageVisual.cpp
   utc-Dali-JsonParser.cpp
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-GridLayout.cpp b/automated-tests/src/dali-toolkit/utc-Dali-GridLayout.cpp
new file mode 100644 (file)
index 0000000..4950241
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2018 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 <toolkit-event-thread-callback.h>
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/layouting/absolute-layout.h>
+#include <dali-toolkit/devel-api/layouting/grid.h>
+#include <dali-toolkit/devel-api/layouting/layout-item-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+#include <../custom-layout.h>
+
+#include <layout-utils.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_grid_layouting_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_grid_layouting_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliLayouting_GridLayout01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_GridLayout01 2 Column, 4 Items");
+
+  const auto NUMBER_OF_COLUMNS = 2;
+  const auto NUMBER_OF_ITEMS = 4;
+
+  tet_printf( "Testing %d columns with %d items\n", NUMBER_OF_COLUMNS, NUMBER_OF_ITEMS );
+
+  Stage stage = Stage::GetCurrent();
+
+  auto rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "AbsoluteLayout" );
+  stage.Add( rootControl );
+
+  auto gridContainer = Control::New();
+  auto gridLayout = Grid::New();
+  gridLayout.SetNumberOfColumns( NUMBER_OF_COLUMNS );
+  gridContainer.SetName( "GridLayout");
+  DevelControl::SetLayout( gridContainer, gridLayout );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+
+  std::vector< Control > controls;
+  for( auto i=0; i < NUMBER_OF_ITEMS; i++ )
+  {
+    controls.push_back( CreateLeafControl( 100, 100 ) );
+  }
+
+  for( auto&& iter : controls )
+  {
+    gridContainer.Add( iter );
+  }
+
+  rootControl.Add( gridContainer );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+ // Grid will layout first 2 items on first row then last 2 on second row.
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  // Item sizes will not be changed
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_printf( "Confirm number of columns is as set\n");
+  DALI_TEST_EQUALS( gridLayout.GetNumberOfColumns(), NUMBER_OF_COLUMNS, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_GridLayout02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliLayouting_GridLayout02");
+
+  const auto NUMBER_OF_COLUMNS = 3;
+  const auto NUMBER_OF_ITEMS = 7;
+
+  tet_printf( "Testing %d columns with %d items\n", NUMBER_OF_COLUMNS, NUMBER_OF_ITEMS );
+
+  Stage stage = Stage::GetCurrent();
+
+  auto rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "AbsoluteLayout" );
+  stage.Add( rootControl );
+
+  auto gridContainer = Control::New();
+  auto gridLayout = Grid::New();
+  gridLayout.SetNumberOfColumns( NUMBER_OF_COLUMNS );
+  gridContainer.SetName( "GridLayout");
+  DevelControl::SetLayout( gridContainer, gridLayout );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+
+  std::vector< Control > controls;
+  for( auto i=0; i < NUMBER_OF_ITEMS; i++ )
+  {
+    controls.push_back( CreateLeafControl( 100, 100 ) );
+  }
+
+  for( auto&& iter : controls )
+  {
+    gridContainer.Add( iter );
+  }
+
+  rootControl.Add( gridContainer );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  // grid  layouts out 3 items per row, which is 480x800.
+  // Row 1
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 200.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  // Row 2
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 200.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  // Row 3
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 200.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_GridLayout03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_GridLayout03 Grid Padding");
+
+  const auto NUMBER_OF_COLUMNS = 2;
+  const auto NUMBER_OF_ITEMS = 4;
+
+  tet_printf( "Testing %d columns with %d items\n", NUMBER_OF_COLUMNS, NUMBER_OF_ITEMS );
+
+  Extents GRID_PADDING( Extents( 10, 10, 20, 20 ) ); // start,end,top,bottom
+
+  tet_printf( "Testing with Padding 10,10,20,20\n");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "AbsoluteLayout" );
+  stage.Add( rootControl );
+
+  auto gridContainer = Control::New();
+  auto gridLayout = Grid::New();
+  gridLayout.SetNumberOfColumns( NUMBER_OF_COLUMNS );
+  gridContainer.SetName( "GridLayout");
+  DevelControl::SetLayout( gridContainer, gridLayout );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  gridContainer.SetProperty( Control::Property::PADDING, GRID_PADDING );
+
+  std::vector< Control > controls;
+  for( auto i=0; i < NUMBER_OF_ITEMS; i++ )
+  {
+    controls.push_back( CreateLeafControl( 100, 100 ) );
+  }
+
+  for( auto&& iter : controls )
+  {
+    gridContainer.Add( iter );
+  }
+
+  rootControl.Add( gridContainer );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline(" UtcDaliLayouting_GridLayout03 Grid Padding 2 Column, 4 Items");
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f + GRID_PADDING.start , 0.0f + GRID_PADDING.top, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f + GRID_PADDING.start, 0.0f + GRID_PADDING.top, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f + GRID_PADDING.start, 100.0f + GRID_PADDING.top , 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f + GRID_PADDING.start, 100.0f + GRID_PADDING.top, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliLayouting_GridLayout03 Size of Grid should include padding");
+  DALI_TEST_EQUALS( gridContainer.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f * NUMBER_OF_COLUMNS + GRID_PADDING.start + + GRID_PADDING.end,
+                                                                                 100.0f * ( NUMBER_OF_ITEMS / NUMBER_OF_COLUMNS ) +
+                                                                                 GRID_PADDING.top + GRID_PADDING.bottom,
+                                                                                 0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliLayouting_GridLayout03 Item sizes unchanged");
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliLayouting_GridLayout04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_GridLayout04 Child Margin");
+
+  const auto NUMBER_OF_COLUMNS = 2;
+  const auto NUMBER_OF_ITEMS = 4;
+
+  tet_printf( "Testing %d columns with %d items\n", NUMBER_OF_COLUMNS, NUMBER_OF_ITEMS );
+
+  Extents GRID_PADDING( Extents( 10, 10, 20, 20 ) ); // start,end,top,bottom
+  Extents ITEM_MARGIN( Extents( 10, 10, 5, 5 ) ); // start,end,top,bottom
+
+  tet_printf( "Testing with Margin 10,10,5,5\n");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "AbsoluteLayout" );
+  stage.Add( rootControl );
+
+  auto gridContainer = Control::New();
+  auto gridLayout = Grid::New();
+  gridLayout.SetNumberOfColumns( NUMBER_OF_COLUMNS );
+  gridContainer.SetName( "GridLayout");
+  DevelControl::SetLayout( gridContainer, gridLayout );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  gridContainer.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION,  ChildLayoutData::WRAP_CONTENT );
+  gridContainer.SetProperty( Control::Property::PADDING, GRID_PADDING );
+
+  std::vector< Control > controls;
+  for( auto i=0; i < NUMBER_OF_ITEMS; i++ )
+  {
+    auto control = CreateLeafControl( 100, 100 );
+    control.SetProperty(Toolkit::Control::Property::MARGIN, ITEM_MARGIN );
+    controls.push_back( control );
+  }
+
+  for( auto&& iter : controls )
+  {
+    gridContainer.Add( iter );
+  }
+
+  rootControl.Add( gridContainer );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ),
+                    Vector3( 0.0f + GRID_PADDING.start + ITEM_MARGIN.start,
+                    0.0f + GRID_PADDING.top + ITEM_MARGIN.top,
+                    0.0f ),
+                    0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ),
+                    Vector3( 100.0f + GRID_PADDING.start + ITEM_MARGIN.start *2 + ITEM_MARGIN.end,
+                    0.0f + GRID_PADDING.top + ITEM_MARGIN.top,
+                    0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ),
+                    Vector3( 0.0f + GRID_PADDING.start + ITEM_MARGIN.start,
+                    100.0f + GRID_PADDING.top + ITEM_MARGIN.top*2 + ITEM_MARGIN.bottom,
+                    0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ),
+                    Vector3( 100.0f + GRID_PADDING.start + ITEM_MARGIN.start*2 + ITEM_MARGIN.end,
+                    100.0f + GRID_PADDING.top + ITEM_MARGIN.top*2 + ITEM_MARGIN.bottom,
+                    0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliLayouting_GridLayout03 Size of Grid should include padding and margins");
+
+  const auto NUMBER_OF_ROWS = ( NUMBER_OF_ITEMS / NUMBER_OF_COLUMNS );
+
+  DALI_TEST_EQUALS( gridContainer.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f * NUMBER_OF_COLUMNS + GRID_PADDING.start + GRID_PADDING.end +
+                                                                                          ITEM_MARGIN.start *NUMBER_OF_COLUMNS + ITEM_MARGIN.end *NUMBER_OF_COLUMNS,
+                                                                                          100.0f * NUMBER_OF_ROWS +
+                                                                                          GRID_PADDING.top + GRID_PADDING.bottom +
+                                                                                          ITEM_MARGIN.bottom *NUMBER_OF_ROWS + ITEM_MARGIN.bottom *NUMBER_OF_ROWS,
+                                                                                          0.0f ), 0.0001f, TEST_LOCATION );
+
+  tet_infoline(" UtcDaliLayouting_GridLayout03 Item sizes unchanged");
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliLayouting_GridLayoutDownCast(void)
+{
+  TestApplication application;
+  tet_infoline(" UtcDaliLayouting_GridLayoutDownCast - Testing Downcast");
+
+  Grid gridLayout = Grid::New();
+
+  LayoutGroup layoutGroup( gridLayout );
+
+  Grid gridLayoutCandidate = Grid::DownCast( layoutGroup );
+  DALI_TEST_CHECK( gridLayoutCandidate );
+
+  END_TEST;
+}
\ No newline at end of file
index e974720..754c815 100755 (executable)
@@ -35,6 +35,7 @@ devel_api_src_files = \
   $(devel_api_src_dir)/layouting/flex-layout.cpp \
   $(devel_api_src_dir)/layouting/absolute-layout.cpp \
   $(devel_api_src_dir)/layouting/linear-layout.cpp \
+  $(devel_api_src_dir)/layouting/grid.cpp \
   $(devel_api_src_dir)/layouting/layout-item.cpp \
   $(devel_api_src_dir)/layouting/layout-item-impl.cpp \
   $(devel_api_src_dir)/layouting/layout-controller.cpp \
@@ -86,6 +87,7 @@ devel_api_layouting_header_files = \
   $(devel_api_src_dir)/layouting/absolute-layout.h \
   $(devel_api_src_dir)/layouting/child-layout-data.h \
   $(devel_api_src_dir)/layouting/flex-layout.h \
+  $(devel_api_src_dir)/layouting/grid.h \
   $(devel_api_src_dir)/layouting/linear-layout.h \
   $(devel_api_src_dir)/layouting/layout-child-impl.h \
   $(devel_api_src_dir)/layouting/layout-controller.h \
diff --git a/dali-toolkit/devel-api/layouting/grid.cpp b/dali-toolkit/devel-api/layouting/grid.cpp
new file mode 100644 (file)
index 0000000..1d9958d
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/devel-api/layouting/grid.h>
+
+//EXTERNAL HEADERS
+//INTERNAL HEADERS
+#include <dali-toolkit/internal/layouting/grid-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+Grid::Grid()
+{
+}
+
+Grid Grid::New()
+{
+  Internal::GridPtr internal = Internal::Grid::New();
+  return Grid( internal.Get() );
+}
+
+Grid Grid::DownCast( BaseHandle handle )
+{
+  return Grid( dynamic_cast< Dali::Toolkit::Internal::Grid*>( handle.GetObjectPtr() ) );
+}
+
+Grid::Grid( const Grid& other )
+: LayoutGroup( other )
+{
+}
+
+Grid& Grid::operator=( const Grid& other )
+{
+  if( &other != this )
+  {
+    LayoutGroup::operator=( other );
+  }
+  return *this;
+}
+
+void Grid::SetNumberOfColumns( int columns )
+{
+  GetImplementation(*this).SetNumberOfColumns( columns );
+}
+
+int Grid::GetNumberOfColumns() const
+{
+  return GetImplementation(*this).GetNumberOfColumns();
+}
+
+Grid::Grid( Dali::Toolkit::Internal::Grid* object )
+: LayoutGroup( object )
+{
+}
+
+} // namespace Toolkit
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/devel-api/layouting/grid.h b/dali-toolkit/devel-api/layouting/grid.h
new file mode 100644 (file)
index 0000000..e26b93f
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_GRID_LAYOUT_H
+#define DALI_TOOLKIT_LAYOUTING_GRID_LAYOUT_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali-toolkit/devel-api/layouting/layout-group.h>
+#include <dali-toolkit/devel-api/layouting/layout-size.h>
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Grid;
+}
+
+/**
+ * @brief
+ * This class implements a horizontal box layout, automatically handling
+ * right to left or left to right direction change.
+ */
+class DALI_TOOLKIT_API Grid : public LayoutGroup
+{
+public:
+
+  /**
+   * @brief Creates an uninitialized Grid handle.
+   *
+   * Initialize it using Grid::New().
+   * Calling member functions with an uninitialized handle is not allowed.
+   */
+  Grid();
+
+  /**
+   * @brief Creates a Grid object.
+   */
+  static Grid New();
+
+  /**
+   * @brief Downcasts a handle to a Grid handle.
+   *
+   * If handle points to a Grid, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+
+   * @param[in] handle to an object
+   * @return Handle to a Grid or an uninitialized handle
+   */
+  static Grid DownCast( BaseHandle handle );
+
+  /**
+   * @brief Copy constructor
+   */
+  Grid( const Grid& other );
+
+  /**
+   * @brief Assigment operator
+   */
+  Grid& operator=( const Grid& other );
+
+  /**
+   * @brief Default destructor.
+   *
+   * This is non-virtual, since derived Handle types must not contain data or virtual methods
+   */
+  ~Grid()=default;
+
+  /**
+   * @brief Set the number of columns in the Grid.
+   * @param[in] columns number of columns,
+   */
+  void SetNumberOfColumns( int columns );
+
+  /**
+   *  @brief Get the number of columns in the grid.
+   *  @return the number of columns.
+   */
+  int GetNumberOfColumns() const;
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by Grid::New() methods.
+   *
+   * @param[in] actor A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL Grid( Internal::Grid* body );
+  /// @endcond
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_GRID_LAYOUT_H
index 328d1d6..6475502 100755 (executable)
@@ -14,6 +14,8 @@ toolkit_src_files = \
    $(toolkit_src_dir)/layouting/flex-layout-impl.cpp \
    $(toolkit_src_dir)/layouting/absolute-layout-impl.cpp \
    $(toolkit_src_dir)/layouting/linear-layout-impl.cpp \
+   $(toolkit_src_dir)/layouting/grid-locations.cpp \
+   $(toolkit_src_dir)/layouting/grid-impl.cpp \
    $(toolkit_src_dir)/layouting/layout-item-data-impl.cpp \
    $(toolkit_src_dir)/layouting/layout-group-data-impl.cpp \
    $(toolkit_src_dir)/layouting/layout-controller-debug.cpp \
diff --git a/dali-toolkit/internal/layouting/grid-impl.cpp b/dali-toolkit/internal/layouting/grid-impl.cpp
new file mode 100644 (file)
index 0000000..a83ed99
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/layouting/grid-impl.h>
+
+//EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/extents.h>
+#include <dali/public-api/actors/actor.h>
+
+//INTERNAL HEADERS
+#include <dali-toolkit/devel-api/layouting/layout-item.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-length.h>
+#include <dali-toolkit/internal/layouting/grid-locations.h>
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+GridPtr Grid::New()
+{
+  GridPtr layout( new Grid() );
+  return layout;
+}
+
+Grid::Grid()
+: LayoutGroup(),
+  mTotalHeight( 0 ),
+  mTotalWidth( 0 ),
+  mNumColumns( AUTO_FIT ),
+  mNumRows( AUTO_FIT ),
+  mRequestedColumnWidth( 0 ),
+  mRequestedNumColumns( AUTO_FIT )
+{
+  mLocations = GridLocations::New();
+}
+
+Grid::~Grid(){}
+
+void Grid::SetNumberOfColumns( int columns )
+{
+  mRequestedNumColumns = columns;
+  // Store value and Relayout if changed.
+  if( columns != mNumColumns )
+  {
+    mNumColumns = columns;
+    RequestLayout();
+  }
+}
+
+int Grid::GetNumberOfColumns() const
+{
+  return mNumColumns;
+}
+
+void Grid::DetermineNumberOfColumns( int availableSpace )
+{
+  if( mRequestedNumColumns == AUTO_FIT )
+  {
+    if( availableSpace > 0 )
+    {
+      // Can only calculate number of columns if a column width has been set
+      mNumColumns = ( mRequestedColumnWidth > 0 ) ? ( availableSpace / mRequestedColumnWidth ) : 1;
+    }
+  }
+}
+
+void Grid::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+  DALI_LOG_STREAM( gLogFilter, Debug::Verbose,
+                   "Grid::OnMeasure Actor Id:" <<  Actor::DownCast(GetOwner()).GetId() <<
+                   " Owner:" <<  Actor::DownCast(GetOwner()).GetName() <<
+                   " MeasureSpecs( width:"<<widthMeasureSpec<<", height:"<<heightMeasureSpec );
+
+  auto gridWidthMode = widthMeasureSpec.GetMode();
+  auto gridHeightMode = heightMeasureSpec.GetMode();
+  LayoutLength widthSize = widthMeasureSpec.GetSize();
+  LayoutLength heightSize = heightMeasureSpec.GetSize();
+
+  int availableContentWidth(0);
+  int availableContentHeight(0);
+
+  LayoutLength desiredChildHeight( 0 );
+  LayoutLength desiredChildWidth( 0 );
+
+  Extents gridLayoutPadding = GetPadding();
+
+  auto childCount = GetChildCount();
+
+  // WIDTH SPECIFICATIONS
+
+  // measure first child and use it's dimensions for layout measurement
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure MeasureSpec::Mode::EXACTLY or MeasureSpec::Mode::AT_MOST \n" );
+
+  if( childCount > 0 )
+  {
+    auto childLayoutItem = GetChildAt( 0 );
+    if( childLayoutItem )
+    {
+      auto childOwner = childLayoutItem->GetOwner();
+
+      MeasureChild( childLayoutItem, widthMeasureSpec, heightMeasureSpec );
+      desiredChildHeight = childLayoutItem->GetMeasuredHeight();
+      desiredChildWidth = childLayoutItem->GetMeasuredWidth();
+
+      // If child has a margin then add it to desired size
+      Extents childMargin = childOwner.GetProperty<Extents>( Toolkit::Control::Property::MARGIN );
+      desiredChildHeight += childMargin.top + childMargin.bottom;
+      desiredChildWidth += childMargin.start + childMargin.end;
+
+      mTotalWidth = desiredChildWidth * mNumColumns;
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure TotalDesiredWidth(%d) \n", mTotalWidth.mValue );
+    } // Child is LayoutItem
+  } // Child exists
+
+  // Include padding for max and min checks
+  mTotalWidth += gridLayoutPadding.start + gridLayoutPadding.end;
+
+  // Ensure width does not exceed specified atmost width or less than mininum width
+  mTotalWidth = std::max( mTotalWidth, GetSuggestedMinimumWidth() );
+
+  // widthMode EXACTLY so grid must be the given width
+  if( gridWidthMode == MeasureSpec::Mode::EXACTLY || gridWidthMode == MeasureSpec::Mode::AT_MOST )
+  {
+    // In the case of AT_MOST, widthSize is the max limit.
+      mTotalWidth = std::min( mTotalWidth, widthSize );
+  }
+
+  availableContentWidth = mTotalWidth - gridLayoutPadding.start - gridLayoutPadding.end;
+  widthSize = mTotalWidth;
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure availableContentWidth(%d) mTotalWidth(%d) \n",
+                 availableContentWidth,
+                 mTotalWidth.mValue );
+  // HEIGHT SPECIFICATIONS
+
+  // heightMode EXACTLY so grid must be the given height
+  if( gridHeightMode == MeasureSpec::Mode::EXACTLY || gridHeightMode == MeasureSpec::Mode::AT_MOST )
+  {
+    if( childCount > 0 )
+    {
+      mTotalHeight = gridLayoutPadding.top + gridLayoutPadding.bottom;
+
+      for( auto i = 0u; i < childCount; i += mNumColumns )
+      {
+        mTotalHeight += desiredChildHeight;
+      }
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnMeasure TotalDesiredHeight(%d) \n",
+                      mTotalHeight.mValue );
+
+      // Ensure ourHeight does not exceed specified atmost height
+      mTotalHeight = std::min( mTotalHeight, heightSize );
+      mTotalHeight = std::max( mTotalHeight, GetSuggestedMinimumHeight() );
+
+      heightSize = mTotalHeight;
+    } // Child exists
+
+    // In the case of AT_MOST, availableContentHeigth is the max limit.
+    availableContentHeight = heightSize - gridLayoutPadding.top - gridLayoutPadding.bottom;
+  }
+  else
+  {
+    // Grid expands to fit content
+
+    // If number of columns AUTO_FIT then set to 1 column.
+
+    // Calculate numbers of rows, round down result as later check for remainder.
+    mNumRows = childCount / ( ( mNumColumns ) ? mNumColumns : 1 );
+    // If number of cells not cleanly dividable by colums, add another row to house remainder cells.
+    mNumRows += ( childCount %  ( ( mNumColumns ) ? mNumColumns : 1 ) ) ? 1 : 0;
+
+    availableContentHeight = desiredChildHeight * mNumRows;
+  }
+
+  // If number of columns not defined
+  DetermineNumberOfColumns( availableContentWidth );
+
+  // Locations define the start, end,top and bottom of each cell.
+  mLocations->CalculateLocations( mNumColumns, availableContentWidth, availableContentHeight, childCount, 0, 0 );
+
+
+  SetMeasuredDimensions( ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK ),
+                         ResolveSizeAndState( heightSize, heightMeasureSpec,  MeasuredSize::State::MEASURED_SIZE_OK ) );
+}
+
+void Grid::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+  auto owner = GetOwner();
+  auto actor = Actor::DownCast(owner);
+  auto count = GetChildCount();
+
+  GridLocations::LocationVector locations =  mLocations->GetLocations();
+
+  Extents gridLayoutPadding = GetPadding();
+  Extents childMargins;
+
+  // Margin for all children dependant on if set on first child
+  if( count )
+  {
+    LayoutItemPtr childLayout = GetChildAt( 0 );
+    if( childLayout )
+    {
+      auto childOwner = childLayout->GetOwner();
+      if( childOwner )
+      {
+        childMargins = childOwner.GetProperty<Extents>( Toolkit::Control::Property::MARGIN );
+      }
+    }
+  }
+
+  for( unsigned int i = 0; i < count; i++)
+  {
+    // for each child
+    int childIndex = i;
+    LayoutItemPtr childLayout = GetChildAt( childIndex );
+    if( childLayout != nullptr )
+    {
+      // Get start and end position of child x1,x2
+      auto x1 = locations[ i ].xStart;
+      auto x2 = locations[ i ].xEnd;
+
+      // Get top and bottom position of child y1,y2
+      auto y1 = locations[ i ].yTop;
+      auto y2 = locations[ i ].yBottom;
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Grid::OnLayout cellSize(%d,%d) \n", x2 - x1,  y2 - y1);
+
+      // Offset children by the grids padding if present
+      x1 += gridLayoutPadding.start;
+      x2 += gridLayoutPadding.start;
+      y1 += gridLayoutPadding.top;
+      y2 += gridLayoutPadding.top;
+
+      // Offset children by the margin of the first child ( if required ).
+      x1 += childMargins.start;
+      x2 -= childMargins.end;
+      y1 += childMargins.top;
+      y2 -= childMargins.bottom;
+
+      childLayout->Layout( x1, y1, x2, y2 );
+    }
+  }
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/grid-impl.h b/dali-toolkit/internal/layouting/grid-impl.h
new file mode 100644 (file)
index 0000000..6afb3f5
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_GRID_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_GRID_IMPL_H
+
+/*
+ * Copyright (c) 2018 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_HEADERS
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL_HEADERS
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali-toolkit/devel-api/layouting/grid.h>
+#include <dali-toolkit/internal/layouting/grid-locations.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class Grid;
+using GridPtr = IntrusivePtr<Grid>;
+
+class Grid final : public LayoutGroup
+{
+public:
+
+  /**
+   * Creates a pointer to an Internal Grid
+   */
+  static GridPtr New();
+
+  /**
+   * Set grid's the number of columns
+   * @param[in] columns number of columns
+   */
+  void SetNumberOfColumns( int columns );
+
+  /**
+   * Get number of columns, -1 would indicate AUTO_FIT
+   * which means the number has not been set but will be calculated.
+   * @return the number of columns set
+   */
+  int GetNumberOfColumns() const;
+
+  // Movable but not copyable
+  Grid( const Grid& other ) = delete;
+  Grid& operator=( const Grid& other ) = delete;
+  Grid( Grid && ) = default;
+  Grid& operator=( Grid && ) = default;
+
+protected:
+
+  /**
+   * Default Constructor
+   */
+  Grid();
+
+  /**
+   * Destructor
+   */
+  ~Grid();
+
+  /**
+   * @copydoc LayoutItem::OnMeasure
+   */
+  virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) override;
+
+  /**
+   * @copydoc LayoutItem::OnLayout
+   */
+  virtual void OnLayout( bool changed, LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b ) override;
+
+private:
+
+  /**
+   * @brief
+   * For the given availableSpace, calculate or retreive the number of required columns.
+   * @param[in] availableSpace the space available for a child in each column.
+   */
+  void DetermineNumberOfColumns( int availableSpace );
+
+private:
+
+  GridLocationsPtr mLocations;
+
+  LayoutLength mTotalHeight;
+  LayoutLength mTotalWidth;
+
+  const int AUTO_FIT = -1;
+
+  int mNumColumns;
+  int mNumRows;
+
+  int mHorizontalSpacing = 0;
+  int mVerticalSpacing = 0;
+  int mRequestedHorizontalSpacing;
+  int mRequestedColumnWidth;
+  int mRequestedNumColumns;
+  int mRequestedNumRows;
+};
+
+} // namespace Internal
+
+inline Internal::Grid& GetImplementation( Dali::Toolkit::Grid& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "Grid handle is empty" );
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast<Internal::Grid&>( object );
+}
+
+inline const Internal::Grid& GetImplementation( const Dali::Toolkit::Grid& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "Grid handle is empty" );
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast<const Internal::Grid&>( object );
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUTINGInner
\ No newline at end of file
diff --git a/dali-toolkit/internal/layouting/grid-locations.cpp b/dali-toolkit/internal/layouting/grid-locations.cpp
new file mode 100644 (file)
index 0000000..8cb1cca
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/layouting/grid-locations.h>
+
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/devel-api/layouting/layout-item.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_AXIS" );
+#endif
+
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+GridLocationsPtr GridLocations::New()
+{
+  GridLocationsPtr gridAxis( new GridLocations() );
+  return gridAxis;
+}
+
+GridLocations::GridLocations()
+: mLocations()
+{
+}
+
+GridLocations::~GridLocations(){}
+
+void GridLocations::CalculateLocations( int numberOfColumns,
+                                        unsigned int availableWidth,
+                                        unsigned int availableHeight,
+                                        unsigned int numberOfCells,
+                                        unsigned int columnWidth,
+                                        unsigned int rowHeight )
+{
+  mLocations.clear();
+
+  // Calculate width and height of columns and rows.
+
+  // Calculate numbers of rows, round down result as later check for remainder.
+  unsigned int numberOfRows = numberOfCells/numberOfColumns;
+  // If number of cells not cleanly dividable by colums, add another row to house remainder cells.
+  numberOfRows += (numberOfCells%numberOfColumns)?1:0;
+
+  unsigned int maxColumnWidth = availableWidth / numberOfColumns;
+
+  if( columnWidth > 0 )
+  {
+    // Column width supplied so use this unless exceeds available width.
+    columnWidth = std::min( columnWidth, maxColumnWidth );
+  }
+  else
+  {
+    // Column width not supplied so use calculated value
+    columnWidth = maxColumnWidth;
+  }
+
+  unsigned int maxRowHeight = availableHeight / numberOfRows;
+
+  if( rowHeight > 0 )
+  {
+    // Column height supplied so use this unless exceeds available height.
+    rowHeight = std::min( rowHeight, maxRowHeight );
+  }
+  else
+  {
+    // Column height not supplied so use calculated value
+    rowHeight = maxRowHeight;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ColumWidth[%d] RowHeight[%d] NumberOfRows[%d] NumberOfColumns[%d]\n",
+                                              columnWidth, rowHeight, numberOfRows, numberOfColumns );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Remainder[%d]\n", numberOfCells%numberOfColumns );
+
+  int  y1 = 0;
+  int  y2 = y1 + rowHeight;
+
+  // Calculate start, end, top and bottom coordinate of each cell.
+
+  // Iterate rows
+  for( auto i = 0u; i < numberOfRows; i++ )
+  {
+    int x1 = 0;
+    int x2 = x1 + columnWidth;
+
+    // Iterate columns
+    for( auto j = 0; j < numberOfColumns; j++ )
+    {
+      GridLocations::Cell cell( x1, x2, y1, y2 );
+      mLocations.push_back( cell );
+      // Calculate starting x and ending x position of each column
+      x1 = x2;
+      x2 = x2 + columnWidth;
+    }
+
+    // Calculate top y and bottom y position of each row.
+    y1 = y2;
+    y2 = y2 + rowHeight;
+  }
+
+#if defined(DEBUG_ENABLED)
+  std::ostringstream oss;
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GridLocations::CalculateLocations (%d)\n", numberOfCells );
+  for( auto i = 0u; i < numberOfCells; i++ )
+  {
+    DALI_LOG_STREAM( gLogFilter, Debug::Verbose,"x1:"<<mLocations[i].xStart<<" x2:"<<mLocations[i].xEnd<<" y1:"<<mLocations[i].yTop<<" y2:"<<mLocations[i].yBottom);
+  }
+#endif
+}
+
+GridLocations::LocationVector GridLocations::GetLocations()
+{
+#if defined(DEBUG_ENABLED)
+  std::ostringstream oss;
+  auto itemCount = mLocations.size(); // mVerticalLocations mirrors this so same size.
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GridLocations::GetLocations for %u cells\n", itemCount );
+  for( auto i = 0u; i < itemCount; i++ )
+  {
+    DALI_LOG_STREAM( gLogFilter, Debug::Verbose,"x1:"<<mLocations[i].xStart<<" x2:"<<mLocations[i].xEnd<<" y1:"<<mLocations[i].yTop<<" y2:"<<mLocations[i].yBottom);
+  }
+#endif
+
+  return mLocations;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/internal/layouting/grid-locations.h b/dali-toolkit/internal/layouting/grid-locations.h
new file mode 100644 (file)
index 0000000..f1f8b6e
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_GRID_LOCATIONS_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_GRID_LOCATIONS_H
+
+/*
+ * Copyright (c) 2018 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 HEADERS
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/ref-object.h>
+#include <limits.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/devel-api/layouting/layout-item-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class GridLocations;
+using GridLocationsPtr = IntrusivePtr<GridLocations>;
+
+/* @brief This internal class houses the algorithm for computing the locations and size of cells.
+ *
+ * A Grid layout uses two instances of this class
+ * distinguished by the "horizontal" flag which is true for the horizontal axis and false
+ * for the vertical one.
+ */
+
+class GridLocations : public RefObject
+{
+
+public:
+
+  static const int UNDEFINED = INT_MIN;
+
+  static const unsigned int HORIZONTAL = 0;
+  static const unsigned int VERTICAL = 1;
+
+  struct Cell
+  {
+    int xStart;
+    int xEnd;
+    int yTop;
+    int yBottom;
+    int explictlyDefined;
+
+    Cell( int x1, int x2, int y1, int y2): xStart(x1), xEnd(x2), yTop(y1), yBottom(y2){};
+  };
+
+  typedef std::vector< Cell > LocationVector;
+
+public:
+
+  static GridLocationsPtr New();
+
+  /*
+   * Uses the given parameters to calculate the x,y coordinates of each cell and cell size.
+   */
+  void CalculateLocations( int numberOfColumns, unsigned int availableWidth,
+                           unsigned int availableHeight, unsigned int numberOfCells,
+                           unsigned int columnWidth, unsigned int rowHeight );
+
+  LocationVector GetLocations();
+
+private:
+
+  GridLocations();
+  ~GridLocations();
+  GridLocations( const GridLocations& other ) = delete;
+  GridLocations& operator=( const GridLocations& other ) = delete;
+
+private:
+
+  LocationVector mLocations;
+
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUTING_GRID_LOCATIONS_H
\ No newline at end of file