New layouting classes devel/layout-fw
authorDavid Steele <david.steele@samsung.com>
Thu, 19 Apr 2018 10:41:59 +0000 (11:41 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 2 May 2018 15:46:59 +0000 (16:46 +0100)
Rolls up the work done so far into a single patch, to avoid reviewing more code than necessary.
Updated doxygen comments.

The layout structure has been streamlined to ensure new layout classes have to do as little work
as possible; concentrating on the child-properties & measure/layout steps.

Test cases for Hbox/VboxLayout test classes are available - these 2 should be rolled up into a single
LinearLayout class (As per NUI/Android).

Change-Id: I72697b22c6cf8f08d197a0418a288b2646148308
Signed-off-by: David Steele <david.steele@samsung.com>
45 files changed:
.gitignore
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h
automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp [new file with mode: 0644]
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/devel-api/controls/control-devel.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/layouting/child-layout-data.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/hbox-layout.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/hbox-layout.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-base-impl.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-base-impl.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-base.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-base.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-controller.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-controller.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-group-impl.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-group-impl.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-group.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-group.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-length.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-parent-impl.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/layout-size.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/measure-spec.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/measured-size.h [new file with mode: 0644]
dali-toolkit/devel-api/layouting/vbox-layout.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/vbox-layout.h [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/file.list
dali-toolkit/internal/layouting/hbox-layout-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/hbox-layout-impl.h [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-base-data-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-base-data-impl.h [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-controller-debug.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-controller-debug.h [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-controller-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-controller-impl.h [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-group-data-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/layout-group-data-impl.h [new file with mode: 0644]
dali-toolkit/internal/layouting/vbox-layout-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/layouting/vbox-layout-impl.h [new file with mode: 0644]

index d2fa7ba..1f638ab 100644 (file)
@@ -37,3 +37,5 @@ dali.doxy
 /build/tizen/.cov
 /build/desktop
 /packaging/home*
+.vscode/
+core
index c754d35..a839b3f 100755 (executable)
@@ -7,110 +7,110 @@ SET(CAPI_LIB "dali-toolkit")
 
 # List of test case sources (Only these get parsed for test cases)
 SET(TC_SOURCES
-   utc-Dali-Alignment.cpp
-   utc-Dali-AnimatedImageVisual.cpp
-   utc-Dali-BloomView.cpp
-   utc-Dali-BubbleEmitter.cpp
-   utc-Dali-Builder.cpp
-   utc-Dali-CheckBoxButton.cpp
-   utc-Dali-ConfirmationPopup.cpp
-   utc-Dali-CubeTransitionEffect.cpp
-   utc-Dali-EffectsView.cpp
-   utc-Dali-FlexContainer.cpp
-   utc-Dali-GaussianBlurView.cpp
-   utc-Dali-ImageView.cpp
-   utc-Dali-ImageVisual.cpp
-   utc-Dali-JsonParser.cpp
-   utc-Dali-KeyInputFocusManager.cpp
-   utc-Dali-PageTurnView.cpp
-   utc-Dali-Script.cpp
-   utc-Dali-ScrollBar.cpp
-   utc-Dali-ScrollView.cpp
-   utc-Dali-ShaderEffects.cpp
-   utc-Dali-ShadowView.cpp
-   utc-Dali-Slider.cpp
-   utc-Dali-TableView.cpp
-   utc-Dali-TextEditor.cpp
-   utc-Dali-TextField.cpp
-   utc-Dali-TextLabel.cpp
-   utc-Dali-TextSelectionPopup.cpp
-   utc-Dali-TextSelectionPopupMirroringLTR.cpp
-   utc-Dali-TextSelectionPopupMirroringRTL.cpp
-   utc-Dali-TextureManager.cpp
-   utc-Dali-ToolBar.cpp
-   utc-Dali-Tooltip.cpp
-   utc-Dali-TransitionData.cpp
-   utc-Dali-Button.cpp
-   utc-Dali-Control.cpp
-   utc-Dali-ControlImpl.cpp
-   utc-Dali-AccessibilityManager.cpp
-   utc-Dali-ItemLayout.cpp
-   utc-Dali-ItemView.cpp
-   utc-Dali-KeyboardFocusManager.cpp
-   utc-Dali-Magnifier.cpp
-   utc-Dali-NavigationView.cpp
-   utc-Dali-Popup.cpp
-   utc-Dali-ProgressBar.cpp
-   utc-Dali-PushButton.cpp
-   utc-Dali-RadioButton.cpp
-   utc-Dali-ToggleButton.cpp
-   utc-Dali-ScrollViewEffect.cpp
-   utc-Dali-SuperBlurView.cpp
-   utc-Dali-Toolkit.cpp
-   utc-Dali-Model3dView.cpp
-   utc-Dali-Visual.cpp
-   utc-Dali-VisualFactory.cpp
-   utc-Dali-ImageAtlas.cpp
-   utc-Dali-VideoView.cpp
-   utc-Dali-AsyncImageLoader.cpp
-   utc-Dali-SyncImageLoader.cpp
-   utc-Dali-ControlWrapper.cpp
+  utc-Dali-Layouting.cpp
+  utc-Dali-Alignment.cpp
+  utc-Dali-AnimatedImageVisual.cpp
+  utc-Dali-BloomView.cpp
+  utc-Dali-BubbleEmitter.cpp
+  utc-Dali-Builder.cpp
+  utc-Dali-CheckBoxButton.cpp
+  utc-Dali-ConfirmationPopup.cpp
+  utc-Dali-CubeTransitionEffect.cpp
+  utc-Dali-EffectsView.cpp
+  utc-Dali-FlexContainer.cpp
+  utc-Dali-GaussianBlurView.cpp
+  utc-Dali-ImageView.cpp
+  utc-Dali-ImageVisual.cpp
+  utc-Dali-JsonParser.cpp
+  utc-Dali-KeyInputFocusManager.cpp
+  utc-Dali-PageTurnView.cpp
+  utc-Dali-Script.cpp
+  utc-Dali-ScrollBar.cpp
+  utc-Dali-ScrollView.cpp
+  utc-Dali-ShaderEffects.cpp
+  utc-Dali-ShadowView.cpp
+  utc-Dali-Slider.cpp
+  utc-Dali-TableView.cpp
+  utc-Dali-TextEditor.cpp
+  utc-Dali-TextField.cpp
+  utc-Dali-TextLabel.cpp
+  utc-Dali-TextSelectionPopup.cpp
+  utc-Dali-TextSelectionPopupMirroringLTR.cpp
+  utc-Dali-TextSelectionPopupMirroringRTL.cpp
+  utc-Dali-TextureManager.cpp
+  utc-Dali-ToolBar.cpp
+  utc-Dali-Tooltip.cpp
+  utc-Dali-TransitionData.cpp
+  utc-Dali-Button.cpp
+  utc-Dali-Control.cpp
+  utc-Dali-ControlImpl.cpp
+  utc-Dali-AccessibilityManager.cpp
+  utc-Dali-ItemLayout.cpp
+  utc-Dali-ItemView.cpp
+  utc-Dali-KeyboardFocusManager.cpp
+  utc-Dali-Magnifier.cpp
+  utc-Dali-NavigationView.cpp
+  utc-Dali-Popup.cpp
+  utc-Dali-ProgressBar.cpp
+  utc-Dali-PushButton.cpp
+  utc-Dali-RadioButton.cpp
+  utc-Dali-ToggleButton.cpp
+  utc-Dali-ScrollViewEffect.cpp
+  utc-Dali-SuperBlurView.cpp
+  utc-Dali-Toolkit.cpp
+  utc-Dali-Model3dView.cpp
+  utc-Dali-Visual.cpp
+  utc-Dali-VisualFactory.cpp
+  utc-Dali-ImageAtlas.cpp
+  utc-Dali-VideoView.cpp
+  utc-Dali-AsyncImageLoader.cpp
+  utc-Dali-SyncImageLoader.cpp
+  utc-Dali-ControlWrapper.cpp
 )
 
 # Append list of test harness files (Won't get parsed for test cases)
 LIST(APPEND TC_SOURCES
-   dali-toolkit-test-utils/toolkit-adaptor.cpp
-   dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
-   dali-toolkit-test-utils/toolkit-application.cpp
-   dali-toolkit-test-utils/toolkit-clipboard.cpp
-   dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
-   dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
-   dali-toolkit-test-utils/toolkit-environment-variable.cpp
-   dali-toolkit-test-utils/toolkit-input-method-context.cpp
-   dali-toolkit-test-utils/toolkit-orientation.cpp
-   dali-toolkit-test-utils/toolkit-physical-keyboard.cpp
-   dali-toolkit-test-utils/toolkit-style-monitor.cpp
-   dali-toolkit-test-utils/toolkit-singleton-service.cpp
-   dali-toolkit-test-utils/toolkit-timer.cpp
-   dali-toolkit-test-utils/toolkit-tts-player.cpp
-   dali-toolkit-test-utils/toolkit-native-image-source.cpp
-   dali-toolkit-test-utils/toolkit-video-player.cpp
-   dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp
-   dali-toolkit-test-utils/dali-test-suite-utils.cpp
-   dali-toolkit-test-utils/dummy-control.cpp
-   dali-toolkit-test-utils/mesh-builder.cpp
-   dali-toolkit-test-utils/test-actor-utils.cpp
-   dali-toolkit-test-utils/test-animation-data.cpp
-   dali-toolkit-test-utils/test-application.cpp
-   dali-toolkit-test-utils/test-button.cpp
-   dali-toolkit-test-utils/test-harness.cpp
-   dali-toolkit-test-utils/test-gesture-manager.cpp
-   dali-toolkit-test-utils/test-gl-abstraction.cpp
-   dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
-   dali-toolkit-test-utils/test-platform-abstraction.cpp
-   dali-toolkit-test-utils/test-render-controller.cpp
-   dali-toolkit-test-utils/test-trace-call-stack.cpp
-   dali-toolkit-test-utils/test-native-image.cpp
+  dali-toolkit-test-utils/toolkit-adaptor.cpp
+  dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
+  dali-toolkit-test-utils/toolkit-application.cpp
+  dali-toolkit-test-utils/toolkit-clipboard.cpp
+  dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
+  dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
+  dali-toolkit-test-utils/toolkit-environment-variable.cpp
+  dali-toolkit-test-utils/toolkit-input-method-context.cpp
+  dali-toolkit-test-utils/toolkit-orientation.cpp
+  dali-toolkit-test-utils/toolkit-physical-keyboard.cpp
+  dali-toolkit-test-utils/toolkit-style-monitor.cpp
+  dali-toolkit-test-utils/toolkit-singleton-service.cpp
+  dali-toolkit-test-utils/toolkit-timer.cpp
+  dali-toolkit-test-utils/toolkit-tts-player.cpp
+  dali-toolkit-test-utils/toolkit-native-image-source.cpp
+  dali-toolkit-test-utils/toolkit-video-player.cpp
+  dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp
+  dali-toolkit-test-utils/dali-test-suite-utils.cpp
+  dali-toolkit-test-utils/dummy-control.cpp
+  dali-toolkit-test-utils/mesh-builder.cpp
+  dali-toolkit-test-utils/test-actor-utils.cpp
+  dali-toolkit-test-utils/test-animation-data.cpp
+  dali-toolkit-test-utils/test-application.cpp
+  dali-toolkit-test-utils/test-button.cpp
+  dali-toolkit-test-utils/test-harness.cpp
+  dali-toolkit-test-utils/test-gesture-manager.cpp
+  dali-toolkit-test-utils/test-gl-abstraction.cpp
+  dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+  dali-toolkit-test-utils/test-platform-abstraction.cpp
+  dali-toolkit-test-utils/test-render-controller.cpp
+  dali-toolkit-test-utils/test-trace-call-stack.cpp
+  dali-toolkit-test-utils/test-native-image.cpp
 )
 
-
 PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
-    dali-core
-    dali-adaptor
-    dali-toolkit
+  dali-core
+  dali-adaptor
+  dali-toolkit
 )
 
-ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror )
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED)
 ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
 
 ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
index d8efd70..4f484a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * 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.
@@ -15,7 +15,7 @@
  *
  */
 
-#include <dali/devel-api/adaptor-framework/singleton-service.h>
+#include <toolkit-singleton-service.h>
 
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/base-object.h>
@@ -74,6 +74,13 @@ public:
     if( singleton )
     {
       mSingletonContainer.insert( SingletonPair( info.name(), singleton ) );
+
+      Integration::Processor* processor = dynamic_cast<Integration::Processor*>( &singleton.GetBaseObject() );
+      if( processor )
+      {
+        Integration::Core& core = mTestApplication->GetCore();
+        core.RegisterProcessor( *processor );
+      }
     }
   }
 
@@ -100,6 +107,11 @@ public:
     return object;
   }
 
+  void SetApplication( Dali::TestApplication& testApplication )
+  {
+    mTestApplication = &testApplication;
+  }
+
 private:
 
   /**
@@ -132,6 +144,7 @@ private:
   typedef SingletonContainer::const_iterator SingletonConstIter;
 
   SingletonContainer mSingletonContainer; ///< The container to look up singleton by its type name
+  TestApplication* mTestApplication;
 };
 
 } // namespace Adaptor
@@ -192,3 +205,14 @@ SingletonService::SingletonService( Internal::Adaptor::SingletonService* singlet
 }
 
 } // namespace Dali
+
+
+namespace Test
+{
+
+void SetApplication( Dali::SingletonService singletonService, TestApplication& testApplication )
+{
+  GetImplementation( singletonService ).SetApplication( testApplication );
+}
+
+} // Test
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.h
new file mode 100644 (file)
index 0000000..7f57f55
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef DALI_TOOLKIT_TEST_SINGLETON_SERVICE_H
+#define DALI_TOOLKIT_TEST_SINGLETON_SERVICE_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/devel-api/adaptor-framework/singleton-service.h>
+#include "test-application.h"
+
+namespace Test
+{
+
+void SetApplication( Dali::SingletonService singletonService, TestApplication& testApplication );
+
+} // Test
+
+#endif //DALI_TOOLKIT_TEST_SINGLETON_SERVICE_H
index 5cc5bef..1301b8f 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_TOOLKIT_TEST_APPLICATION_H__
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * 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.
@@ -23,6 +23,7 @@
 #include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/integration-api/adaptors/adaptor.h>
 #include <toolkit-adaptor-impl.h>
+#include <toolkit-singleton-service.h>
 
 namespace Dali
 {
@@ -41,6 +42,8 @@ public:
   : TestApplication( false, surfaceWidth, surfaceHeight, horizontalDpi, verticalDpi )
   {
     Initialize();
+    auto singletonService = SingletonService::Get();
+    Test::SetApplication( singletonService, *this );
 
     // set the DPI value for font rendering
     Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Layouting.cpp
new file mode 100644 (file)
index 0000000..7d8586a
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * 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 <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/layouting/hbox-layout.h>
+#include <dali-toolkit/devel-api/layouting/vbox-layout.h>
+//#include <dali-toolkit/internal/controls/control/control-data-impl-debug.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_layouting_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_layouting_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+Control CreateLeafControl( int width, int height )
+{
+  auto control = Control::New();
+  control.SetName( "Leaf" );
+
+  auto pixelBuffer = Devel::PixelBuffer::New( 1, 1, Pixel::RGB888 );
+  unsigned char* pixels = pixelBuffer.GetBuffer();
+  pixels[0] = 0xff;
+  pixels[1] = 0x00;
+  pixels[2] = 0x00;
+  auto texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGB888, 1, 1 );
+  auto pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+  texture.Upload( pixelData );
+  std::string url = TextureManager::AddTexture( texture );
+
+  Property::Map map;
+  map[ Visual::Property::TYPE ] = Visual::IMAGE;
+  map[ ImageVisual::Property::URL ] = url;
+  map[ ImageVisual::Property::DESIRED_WIDTH ] = (float) width;
+  map[ ImageVisual::Property::DESIRED_HEIGHT ] = (float) height;
+  control.SetProperty( Control::Property::BACKGROUND, map );
+  return control;
+}
+
+int UtcDaliLayouting_HboxLayout01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_HboxLayout01");
+
+  Stage stage = Stage::GetCurrent();
+  auto hbox = Control::New();
+  auto hboxLayout = HboxLayout::New();
+  hboxLayout.SetCellPadding( LayoutSize( 10, 0 ) );
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetName( "HBox");
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 40, 40 ) );
+  controls.push_back( CreateLeafControl( 60, 40 ) );
+  controls.push_back( CreateLeafControl( 80, 40 ) );
+  controls.push_back( CreateLeafControl( 100, 40 ) );
+
+  for( auto&& iter : controls )
+  {
+    hbox.Add( iter );
+  }
+  hbox.SetParentOrigin( ParentOrigin::CENTER );
+  hbox.SetAnchorPoint( AnchorPoint::CENTER );
+  stage.Add( hbox );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  // hbox centers elements vertically, it fills test harness stage, which is 480x800.
+  // hbox left justifies elements
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 50.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 120.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 210.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+
+int UtcDaliLayouting_HboxLayout02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_HboxLayout02 Test nested hboxes with default spec of WRAP_CONTENT");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto hbox1 = Control::New();
+  auto hboxLayout1 = HboxLayout::New();
+  DevelControl::SetLayout( hbox1, hboxLayout1 );
+
+  auto hbox2 = Control::New();
+  auto hboxLayout2 = HboxLayout::New();
+  DevelControl::SetLayout( hbox2, hboxLayout2 );
+
+  hbox1.SetName( "HBox1");
+  hbox2.SetName( "HBox2");
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 20, 40 ) );
+  controls.push_back( CreateLeafControl( 30, 50 ) );
+  controls.push_back( CreateLeafControl( 40, 60 ) );
+  controls.push_back( CreateLeafControl( 50, 70 ) );
+
+  controls.push_back( CreateLeafControl( 25, 40 ) );
+  controls.push_back( CreateLeafControl( 35, 50 ) );
+  controls.push_back( CreateLeafControl( 45, 60 ) );
+  controls.push_back( CreateLeafControl( 55, 70 ) );
+
+  int counter=0;
+  for( auto&& iter : controls )
+  {
+    if( counter < 4 )
+    {
+      hbox1.Add( iter );
+    }
+    else
+    {
+      hbox2.Add( iter );
+    }
+    ++counter;
+  }
+  hbox1.SetParentOrigin( ParentOrigin::CENTER );
+  hbox1.SetAnchorPoint( AnchorPoint::CENTER );
+  hbox2.SetParentOrigin( ParentOrigin::CENTER );
+  hbox2.SetAnchorPoint( AnchorPoint::CENTER );
+
+  auto hbox3 = Control::New();
+  auto hboxLayout3 = HboxLayout::New();
+  DevelControl::SetLayout( hbox3, hboxLayout3 );
+
+  hbox3.SetParentOrigin( ParentOrigin::CENTER );
+  hbox3.SetName( "HBox3");
+  hbox3.Add( hbox1 );
+  hbox3.Add( hbox2 );
+
+  stage.Add( hbox3 );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+
+  // hbox centers elements vertically, it fills test harness stage, which is 480x800.
+  // hbox left justifies elements
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3(  0.0f, 15.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 20.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 50.0f,  5.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 90.0f,  0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 20.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 30.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 50.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3(  0.0f, 15.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 25.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 60.0f,  5.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[7].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 105.0f,  0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 25.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 35.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 45.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[7].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 55.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  // Test hbox1 and 2 are sized to wrap their content
+  DALI_TEST_EQUALS( hbox1.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 140.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox2.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 160.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox1.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 365.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox2.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 140.0f, 365.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  // Test hbox3 matches parent (root layer)
+  DALI_TEST_EQUALS( hbox3.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox3.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliLayouting_HboxLayout03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_HboxLayout03 Test nested hboxes with MATCH_PARENT");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto hbox1 = Control::New();
+  auto hboxLayout1 = HboxLayout::New();
+  DevelControl::SetLayout( hbox1, hboxLayout1 );
+
+  auto hbox2 = Control::New();
+  auto hboxLayout2 = HboxLayout::New();
+  DevelControl::SetLayout( hbox2, hboxLayout2 );
+
+  hbox1.SetName( "HBox1");
+  hbox2.SetName( "HBox2");
+  hbox1.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+  hbox1.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+  hbox2.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+  hbox2.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 20, 40 ) );
+  controls.push_back( CreateLeafControl( 30, 50 ) );
+  controls.push_back( CreateLeafControl( 40, 60 ) );
+  controls.push_back( CreateLeafControl( 50, 70 ) );
+
+  controls.push_back( CreateLeafControl( 25, 40 ) );
+  controls.push_back( CreateLeafControl( 35, 50 ) );
+  controls.push_back( CreateLeafControl( 45, 60 ) );
+  controls.push_back( CreateLeafControl( 55, 70 ) );
+
+  int counter=0;
+  for( auto&& iter : controls )
+  {
+    if( counter < 4 )
+    {
+      hbox1.Add( iter );
+    }
+    else
+    {
+      hbox2.Add( iter );
+    }
+    ++counter;
+  }
+  hbox1.SetParentOrigin( ParentOrigin::CENTER );
+  hbox1.SetAnchorPoint( AnchorPoint::CENTER );
+  hbox2.SetParentOrigin( ParentOrigin::CENTER );
+  hbox2.SetAnchorPoint( AnchorPoint::CENTER );
+
+  auto hbox3 = Control::New();
+  auto hboxLayout3 = HboxLayout::New();
+  DevelControl::SetLayout( hbox3, hboxLayout3);
+
+  hbox3.SetParentOrigin( ParentOrigin::CENTER );
+  hbox3.SetName( "HBox3");
+  hbox3.Add( hbox1 );
+  hbox3.Add( hbox2 );
+
+  stage.Add( hbox3 );
+
+  //std::ostringstream oss;
+  //DumpControlHierarchy( oss, Stage::GetCurrent().GetRootLayer() );
+  //printf("Control hierarchy: \n%s\n", oss.str().c_str() );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+
+  // hbox centers elements vertically, it fills test harness stage, which is 480x800.
+  // hbox left justifies elements
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 20.0f,375.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 50.0f,370.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 90.0f,365.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 20.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 30.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 50.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3(  0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 25.0f, 375.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 60.0f, 370.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[7].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 105.0f,365.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 25.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 35.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 45.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[7].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 55.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( hbox1.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox2.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox1.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox2.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 480.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  // Test hbox3 matches parent (root layer)
+  DALI_TEST_EQUALS( hbox3.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox3.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+
+int UtcDaliLayouting_HboxLayout04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_HboxLayout04 Test nested hboxes with explicit WRAP_CONTENT");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto hbox1 = Control::New();
+  auto hboxLayout1 = HboxLayout::New();
+  DevelControl::SetLayout( hbox1, hboxLayout1 );
+
+  auto hbox2 = Control::New();
+  auto hboxLayout2 = HboxLayout::New();
+  DevelControl::SetLayout( hbox2, hboxLayout2 );
+
+  hbox1.SetName( "HBox1"); // Default spec is to wrap content
+  hbox2.SetName( "HBox2");
+  hbox1.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  hbox1.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  hbox2.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  hbox2.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 80, 40 ) );
+  controls.push_back( CreateLeafControl( 80, 50 ) );
+  controls.push_back( CreateLeafControl( 80, 60 ) );
+  controls.push_back( CreateLeafControl( 80, 70 ) );
+
+  controls.push_back( CreateLeafControl( 80, 40 ) );
+  controls.push_back( CreateLeafControl( 80, 50 ) );
+  controls.push_back( CreateLeafControl( 80, 60 ) );
+  controls.push_back( CreateLeafControl( 80, 70 ) );
+
+  int counter=0;
+  for( auto&& iter : controls )
+  {
+    if( counter < 4 )
+    {
+      hbox1.Add( iter );
+    }
+    else
+    {
+      hbox2.Add( iter );
+    }
+    ++counter;
+  }
+
+  controls[6].SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+  auto hbox3 = Control::New();
+  auto hboxLayout3 = HboxLayout::New();
+  DevelControl::SetLayout( hbox3, hboxLayout3 );
+
+  hbox3.SetParentOrigin( ParentOrigin::CENTER );
+  hbox3.SetName( "HBox3");
+  hbox3.Add( hbox1 );
+  hbox3.Add( hbox2 );
+  stage.Add( hbox3 );
+
+  //std::ostringstream oss;
+  //DumpControlHierarchy( oss, Stage::GetCurrent().GetRootLayer() );
+  //printf("Control hierarchy: \n%s\n", oss.str().c_str() );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 15.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 80.0f,10.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 160.0f, 5.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 240.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3(  0.0f, 15.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 80.0f, 10.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 160.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[7].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 240.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[4].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[5].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[6].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[7].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 80.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( hbox1.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 320.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox2.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 320.0f, 70.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox1.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 365.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox2.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 320.0f, 365.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+
+  // Test hbox3 matches parent (root layer)
+  DALI_TEST_EQUALS( hbox3.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( hbox3.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliLayouting_VboxLayout01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_VboxLayout01");
+
+  Stage stage = Stage::GetCurrent();
+  auto vbox = Control::New();
+  auto vboxLayout = VboxLayout::New();
+  DevelControl::SetLayout( vbox, vboxLayout );
+  vbox.SetName( "Vbox");
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 40, 40 ) );
+  controls.push_back( CreateLeafControl( 60, 60 ) );
+  controls.push_back( CreateLeafControl( 80, 80 ) );
+  controls.push_back( CreateLeafControl( 100, 100 ) );
+
+  for( auto&& iter : controls )
+  {
+    vbox.Add( iter );
+  }
+  vbox.SetParentOrigin( ParentOrigin::CENTER );
+  vbox.SetAnchorPoint( AnchorPoint::CENTER );
+  stage.Add( vbox );
+
+  controls[2].SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+
+  // Check it.
+  DALI_TEST_EQUALS( controls[2].GetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ), Property::Value( ChildLayoutData::MATCH_PARENT ), TEST_LOCATION );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  // vbox centers elements horizontally, it fills test harness stage, which is 480x800.
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 220.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 210.0f, 40.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( 190.0f, 180.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 480.0f, 80.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_VboxLayout02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_VboxLayout01");
+
+  Stage stage = Stage::GetCurrent();
+
+  // @todo Can't set specification properties on root control. Really need to make LayoutController a root
+  // LayoutGroup for this to happen automatically.
+  //
+  // For this test, add an hbox instead
+  auto hbox = Control::New();
+  auto hboxLayout = HboxLayout::New();
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetName( "Hbox");
+  stage.Add( hbox );
+
+  auto vbox = Control::New();
+  auto vboxLayout = VboxLayout::New();
+  DevelControl::SetLayout( vbox, vboxLayout );
+  vbox.SetName( "Vbox");
+  hbox.Add( vbox );
+
+  vbox.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  vbox.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 40, 40 ) );
+  controls.push_back( CreateLeafControl( 60, 60 ) );
+  controls.push_back( CreateLeafControl( 80, 80 ) );
+  controls.push_back( CreateLeafControl( 100, 100 ) );
+
+  for( auto&& iter : controls )
+  {
+    vbox.Add( iter );
+  }
+  vbox.SetParentOrigin( ParentOrigin::CENTER );
+  vbox.SetAnchorPoint( AnchorPoint::CENTER );
+
+  controls[2].SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+
+  // Check it.
+  DALI_TEST_EQUALS( controls[2].GetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ), Property::Value( ChildLayoutData::MATCH_PARENT ), TEST_LOCATION );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( hbox.GetProperty<Vector3>(Actor::Property::POSITION), Vector3(0,0,0),TEST_LOCATION);
+  DALI_TEST_EQUALS( hbox.GetProperty<Vector3>(Actor::Property::SIZE), Vector3(480,800,0),TEST_LOCATION);
+
+  // vbox centers elements horizontally, it should wrap it's content horizontally, i.e. it should take the width of the largest element (100)
+  DALI_TEST_EQUALS( vbox.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( vbox.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  // 3rd control is set to match parent - this should also be 100 wide
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 30.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 20.0f, 40.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( 0.0f, 180.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 80.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_VboxLayout03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_VboxLayout03 test with cell padding set");
+
+  Stage stage = Stage::GetCurrent();
+
+  // @todo Can't set specification properties on root control. Really need to make LayoutController a root
+  // LayoutGroup for this to happen automatically.
+  //
+  // For this test, add an hbox instead
+  auto hbox = Control::New();
+  auto hboxLayout = HboxLayout::New();
+  DevelControl::SetLayout( hbox, hboxLayout );
+  hbox.SetName( "Hbox");
+  stage.Add( hbox );
+
+  auto vbox = Control::New();
+  auto vboxLayout = VboxLayout::New();
+  vboxLayout.SetCellPadding( LayoutSize( 0, 10 ) );
+
+  DALI_TEST_EQUALS( vboxLayout.GetCellPadding(), LayoutSize( 0, 10 ), TEST_LOCATION );
+
+  DevelControl::SetLayout( vbox, vboxLayout );
+  vbox.SetName( "Vbox");
+  hbox.Add( vbox );
+
+  vbox.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+  vbox.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 40, 40 ) );
+  controls.push_back( CreateLeafControl( 60, 60 ) );
+  controls.push_back( CreateLeafControl( 80, 80 ) );
+  controls.push_back( CreateLeafControl( 100, 100 ) );
+
+  for( auto&& iter : controls )
+  {
+    vbox.Add( iter );
+  }
+  vbox.SetParentOrigin( ParentOrigin::CENTER );
+  vbox.SetAnchorPoint( AnchorPoint::CENTER );
+
+  controls[2].SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+
+  // Check it.
+  DALI_TEST_EQUALS( controls[2].GetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ), Property::Value( ChildLayoutData::MATCH_PARENT ), TEST_LOCATION );
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( hbox.GetProperty<Vector3>(Actor::Property::POSITION), Vector3(0,0,0),TEST_LOCATION);
+  DALI_TEST_EQUALS( hbox.GetProperty<Vector3>(Actor::Property::SIZE), Vector3(480,800,0),TEST_LOCATION);
+
+  // vbox centers elements horizontally, it should wrap it's content horizontally, i.e. it should take the width of the largest element (100)
+  DALI_TEST_EQUALS( vbox.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( vbox.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 800.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  // 3rd control is set to match parent - this should also be 100 wide
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 30.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 20.0f, 50.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 120.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 210.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 80.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;
+}
index 542d064..29fe4a0 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2017 Samsung Electronics Co., Ltd.
+# 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.
@@ -144,6 +144,8 @@ develapishadowviewdir =         $(develapicontrolsdir)/shadow-view
 develapisuperblurviewdir =      $(develapicontrolsdir)/super-blur-view
 develapifocusmanagerdir =       $(develapidir)/focus-manager
 develapiimageloaderdir =        $(develapidir)/image-loader
+develapilayoutingdir =          $(develapidir)/layouting
+develapilayoutingcontrolsdir =  $(develapidir)/controls/layouting
 develapiscriptingdir =          $(develapidir)/scripting
 develapishadereffectsdir =      $(develapidir)/shader-effects
 develapistylingdir =            $(develapidir)/styling
@@ -166,6 +168,8 @@ develapieffectsview_HEADERS =       $(devel_api_effects_view_header_files)
 develapifocusmanager_HEADERS =      $(devel_api_focus_manager_header_files)
 develapigaussianblurview_HEADERS =  $(devel_api_gaussian_blur_view_header_files)
 develapiimageloader_HEADERS =       $(devel_api_image_loader_header_files)
+develapilayoutingcontrols_HEADERS = $(devel_api_layouting_controls_header_files)
+develapilayouting_HEADERS =         $(devel_api_layouting_header_files)
 develapimagnifier_HEADERS =         $(devel_api_magnifier_header_files)
 develapinavigationview_HEADERS =    $(devel_api_navigation_view_header_files)
 develapipageturnview_HEADERS =      $(devel_api_page_turn_view_header_files)
index a9a83dd..b5c65e1 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * 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.
@@ -89,6 +89,15 @@ Dali::Animation CreateTransition( Internal::Control& control, const Toolkit::Tra
   return controlDataImpl.CreateTransition( handle );
 }
 
+
+void AddTransitions( Internal::Control& control,
+                     Dali::Animation animation,
+                     const Toolkit::TransitionData& transitionData )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.AddTransitions( animation, transitionData );
+}
+
 void DoAction( Control& control, Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes )
 {
   Internal::Control& controlInternal = Toolkit::Internal::GetImplementation( control );
@@ -101,6 +110,32 @@ void SetInputMethodContext( Internal::Control& control, InputMethodContext& inpu
   Internal::Control::Impl::Get( control ).SetInputMethodContext( inputMethodContext );
 }
 
+Toolkit::LayoutBase GetLayout( Control control )
+{
+  const Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control );
+  const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( internalControl );
+  return Toolkit::LayoutBase( controlDataImpl.GetLayout().Get() );
+}
+
+Toolkit::LayoutBase GetLayout( Internal::Control& control )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  return Toolkit::LayoutBase( controlDataImpl.GetLayout().Get() );
+}
+
+void SetLayout( Internal::Control& control, Toolkit::LayoutBase layout )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.SetLayout( GetImplementation( layout ) );
+}
+
+void SetLayout( Control control, Toolkit::LayoutBase layout )
+{
+  Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control );
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( internalControl );
+  controlDataImpl.SetLayout( GetImplementation( layout ) );
+}
+
 } // namespace DevelControl
 
 } // namespace Toolkit
index 1fece4f..aa47809 100755 (executable)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_DEVEL_H
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * 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.
@@ -23,6 +23,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/devel-api/layouting/layout-base.h>
 
 namespace Dali
 {
@@ -216,6 +217,23 @@ DALI_IMPORT_API void EnableVisual( Internal::Control& control, Dali::Property::I
  */
 DALI_IMPORT_API bool IsVisualEnabled( const Internal::Control& control, Dali::Property::Index index );
 
+
+/**
+ * @brief Add a transition effect on the control to the given animation
+ *
+ * Only generates an animator if the properties described in the transition
+ * data are staged (e.g. the visual is Enabled and the control is on stage).
+ * Otherwise the target values are stored, and will get set onto the properties
+ * when the visual is next staged.
+ *
+ * @param[in] control The control
+ * @param[in] animation The Animation to add valid transitions to
+ * @param[in] transitionData The transition data describing the effect to create
+ */
+DALI_IMPORT_API void AddTransitions( Internal::Control& control,
+                                     Dali::Animation animation,
+                                     const Toolkit::TransitionData& transitionData );
+
 /**
  * @brief Create a transition effect on the control.
  *
@@ -229,7 +247,8 @@ DALI_IMPORT_API bool IsVisualEnabled( const Internal::Control& control, Dali::Pr
  * @return A handle to an animation defined with the given effect, or an empty
  * handle if no properties match.
  */
-DALI_IMPORT_API Dali::Animation CreateTransition( Internal::Control& control, const Toolkit::TransitionData& transitionData );
+DALI_IMPORT_API Dali::Animation CreateTransition( Internal::Control& control,
+                                                  const Toolkit::TransitionData& transitionData );
 
 /**
  * @brief Perform an action on a visual registered to this control.
@@ -251,6 +270,36 @@ DALI_IMPORT_API void DoAction( Control& control, Dali::Property::Index visualInd
  */
 DALI_IMPORT_API void SetInputMethodContext( Internal::Control& control, InputMethodContext& inputMethodContext );
 
+/*
+ * @brief Get the layout associated with this control, if any.
+ *
+ * @return A handle to the layout, or empty.
+ */
+DALI_IMPORT_API Toolkit::LayoutBase GetLayout( Internal::Control& control );
+
+/*
+ * @brief Get the layout associated with a control, if any.
+ *
+ * @return A handle to the layout, or empty.
+ */
+DALI_IMPORT_API Toolkit::LayoutBase GetLayout( Control control );
+
+/**
+ * @brief Set the layout on this control.
+ *
+ * @param[in] control The internal Control to set the layout on
+ * @param[in] layout Pointer to the layout
+ */
+DALI_IMPORT_API void SetLayout( Internal::Control& control, Toolkit::LayoutBase layout );
+
+/**
+ * @brief Set the layout on a control.
+ *
+ * @param[in] control The Control to set the layout on
+ * @param[in] layout Pointer to the layout
+ */
+DALI_IMPORT_API void SetLayout( Control control, Toolkit::LayoutBase layout );
+
 } // namespace DevelControl
 
 } // namespace Toolkit
index a04fc74..e856374 100755 (executable)
@@ -31,6 +31,13 @@ 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/hbox-layout.cpp \
+  $(devel_api_src_dir)/layouting/vbox-layout.cpp \
+  $(devel_api_src_dir)/layouting/layout-base.cpp \
+  $(devel_api_src_dir)/layouting/layout-base-impl.cpp \
+  $(devel_api_src_dir)/layouting/layout-controller.cpp \
+  $(devel_api_src_dir)/layouting/layout-group.cpp \
+  $(devel_api_src_dir)/layouting/layout-group-impl.cpp \
   $(devel_api_src_dir)/scripting/script.cpp \
   $(devel_api_src_dir)/styling/style-manager-devel.cpp \
   $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \
@@ -71,6 +78,19 @@ 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/child-layout-data.h \
+  $(devel_api_src_dir)/layouting/hbox-layout.h \
+  $(devel_api_src_dir)/layouting/vbox-layout.h \
+  $(devel_api_src_dir)/layouting/layout-base.h \
+  $(devel_api_src_dir)/layouting/layout-base-impl.h \
+  $(devel_api_src_dir)/layouting/layout-controller.h \
+  $(devel_api_src_dir)/layouting/layout-group.h \
+  $(devel_api_src_dir)/layouting/layout-group-impl.h \
+  $(devel_api_src_dir)/layouting/layout-length.h \
+  $(devel_api_src_dir)/layouting/layout-size.h \
+  $(devel_api_src_dir)/layouting/measure-spec.h
+
 devel_api_magnifier_header_files = \
   $(devel_api_src_dir)/controls/magnifier/magnifier.h
 
diff --git a/dali-toolkit/devel-api/layouting/child-layout-data.h b/dali-toolkit/devel-api/layouting/child-layout-data.h
new file mode 100644 (file)
index 0000000..f3af733
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_CHILD_LAYOUT_DATA_H
+#define DALI_TOOLKIT_LAYOUTING_CHILD_LAYOUT_DATA_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.
+ */
+
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+// used in property system - must be integer values.
+namespace ChildLayoutData
+{
+static const int MATCH_PARENT = -1; ///< Constant which indicates child size should match parent size
+static const int WRAP_CONTENT = -2; ///< Constant which indicates parent should take the smallest size possible to wrap it's children with their desired size
+
+} // namespace ChildLayoutData
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_CHILD_LAYOUT_DATA_H
diff --git a/dali-toolkit/devel-api/layouting/hbox-layout.cpp b/dali-toolkit/devel-api/layouting/hbox-layout.cpp
new file mode 100644 (file)
index 0000000..7f05745
--- /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/hbox-layout.h>
+
+//EXTERNAL HEADERS
+//INTERNAL HEADERS
+#include <dali-toolkit/internal/layouting/hbox-layout-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+HboxLayout::HboxLayout()
+{
+}
+
+HboxLayout HboxLayout::New()
+{
+  Internal::HboxLayoutPtr internal = Internal::HboxLayout::New();
+  return HboxLayout( internal.Get() );
+}
+
+HboxLayout HboxLayout::DownCast( BaseHandle handle )
+{
+  return HboxLayout( dynamic_cast< Dali::Toolkit::Internal::HboxLayout*>( handle.GetObjectPtr() ) );
+}
+
+HboxLayout::HboxLayout( const HboxLayout& other )
+: LayoutGroup( other )
+{
+}
+
+HboxLayout& HboxLayout::operator=( const HboxLayout& other )
+{
+  if( &other != this )
+  {
+    LayoutGroup::operator=( other );
+  }
+  return *this;
+}
+
+void HboxLayout::SetCellPadding( LayoutSize size )
+{
+  GetImplementation(*this).SetCellPadding( size );
+}
+
+LayoutSize HboxLayout::GetCellPadding()
+{
+  return GetImplementation(*this).GetCellPadding();
+}
+
+HboxLayout::HboxLayout( Dali::Toolkit::Internal::HboxLayout* object )
+: LayoutGroup( object )
+{
+}
+
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/hbox-layout.h b/dali-toolkit/devel-api/layouting/hbox-layout.h
new file mode 100644 (file)
index 0000000..62c4bf7
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_HBOX_LAYOUT_H
+#define DALI_TOOLKIT_LAYOUTING_HBOX_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 HboxLayout;
+}
+
+/**
+ * This class implements a horizontal box layout, automatically handling
+ * right to left or left to right direction change.
+ */
+class DALI_IMPORT_API HboxLayout : public LayoutGroup
+{
+public:
+
+  enum PropertyRange
+  {
+    CHILD_PROPERTY_START_INDEX = LayoutGroup::CHILD_PROPERTY_START_INDEX+100,
+    CHILD_PROPERTY_END_INDEX   = CHILD_PROPERTY_START_INDEX+1000
+  };
+
+  struct Property
+  {
+    // @todo When we can have event-only properties for BaseObject, this will be useful.
+    enum
+    {
+      CELL_PADDING = PROPERTY_REGISTRATION_START_INDEX + 2000
+    };
+  };
+
+  struct ChildProperty
+  {
+    enum
+    {
+      WEIGHT = CHILD_PROPERTY_START_INDEX
+    };
+  };
+
+  /**
+   * @brief Creates an uninitialized HboxLayout handle.
+   *
+   * Initialize it using HboxLayout::New().
+   * Calling member functions with an uninitialized handle is not allowed.
+   */
+  HboxLayout();
+
+  /**
+   * @brief Creates a HboxLayout object.
+   */
+  static HboxLayout New();
+
+  /**
+   * @brief Downcasts a handle to a HboxLayout handle.
+   *
+   * If handle points to a HboxLayout, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+
+   * @param[in] handle to an object
+   * @return Handle to a HboxLayout or an uninitialized handle
+   */
+  static HboxLayout DownCast( BaseHandle handle );
+
+  /**
+   * @brief Copy constructor
+   */
+  HboxLayout( const HboxLayout& other );
+
+  /**
+   * @brief Assigment operator
+   */
+  HboxLayout& operator=( const HboxLayout& other );
+
+  /**
+   * @brief Default destructor.
+   *
+   * This is non-virtual, since derived Handle types must not contain data or virtual methods
+   */
+  ~HboxLayout()=default;
+
+  /**
+   * @brief Set the padding between cells in the layout
+   *
+   * @param[in] size The padding between cells.
+   */
+  void SetCellPadding( LayoutSize size );
+
+  /**
+   * @brief Get the padding between cells in the layout
+   *
+   * @return The padding between cells.
+   */
+  LayoutSize GetCellPadding();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by HboxLayout::New() methods.
+   *
+   * @param[in] actor A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL HboxLayout( Internal::HboxLayout* body );
+  /// @endcond
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_HBOX_LAYOUT_H
diff --git a/dali-toolkit/devel-api/layouting/layout-base-impl.cpp b/dali-toolkit/devel-api/layouting/layout-base-impl.cpp
new file mode 100644 (file)
index 0000000..ebc4bcc
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * 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/integration-api/debug.h>
+
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/layouting/layout-base-impl.h>
+#include <dali-toolkit/internal/layouting/layout-base-data-impl.h>
+
+#if defined(DEBUG_ENABLED)
+    Debug::Filter* gLayoutFilter = Debug::Filter::New( Debug::Verbose, false, "LOG_LAYOUT" );
+#endif
+
+namespace
+{
+const char* WIDTH_SPECIFICATION_NAME( "widthSpecification" );
+const char* HEIGHT_SPECIFICATION_NAME( "heightSpecification" );
+
+const float DEFAULT_TRANSITION_DURATION( 0.5f );
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+LayoutBase::LayoutBase()
+: mImpl( new LayoutBase::Impl() ),
+  mSlotDelegate( this )
+{
+}
+
+LayoutBasePtr LayoutBase::New( Handle& owner )
+{
+  LayoutBasePtr layoutPtr = new LayoutBase();
+  return layoutPtr;
+}
+
+void LayoutBase::Initialize( Handle& owner, const std::string& containerType )
+{
+  mImpl->mOwner = &(owner.GetBaseObject());
+  RegisterChildProperties( containerType );
+  OnInitialize(); // Ensure direct deriving class gets initialized
+  RequestLayout();
+}
+
+Handle LayoutBase::GetOwner() const
+{
+  return Handle::DownCast(BaseHandle(mImpl->mOwner));
+}
+
+void LayoutBase::Unparent()
+{
+  // Enable directly derived types to first remove children
+  OnUnparent();
+
+  // Last, clear owner
+  mImpl->mOwner = NULL;
+}
+
+void LayoutBase::SetAnimateLayout( bool animateLayout )
+{
+  mImpl->mAnimated = animateLayout;
+}
+
+bool LayoutBase::IsLayoutAnimated() const
+{
+  return mImpl->mAnimated;
+}
+
+void LayoutBase::RegisterChildProperties( const std::string& containerType )
+{
+  // Call on derived types
+  auto typeInfo = TypeRegistry::Get().GetTypeInfo( containerType );
+  if( typeInfo )
+  {
+    Property::IndexContainer indices;
+    typeInfo.GetChildPropertyIndices( indices );
+
+    if( std::find( indices.Begin(), indices.End(), Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ) ==
+        indices.End() )
+    {
+      ChildPropertyRegistration( typeInfo.GetName(), WIDTH_SPECIFICATION_NAME,
+                                 Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, Property::INTEGER );
+
+      ChildPropertyRegistration( typeInfo.GetName(), HEIGHT_SPECIFICATION_NAME,
+                                 Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, Property::INTEGER );
+    }
+
+    OnRegisterChildProperties( containerType );
+  }
+}
+
+void LayoutBase::OnRegisterChildProperties( const std::string& containerType )
+{
+}
+
+
+void LayoutBase::Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+  const bool forceLayout = mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
+
+  const bool specChanged =
+    ( widthMeasureSpec  != mImpl->mOldWidthMeasureSpec ) ||
+    ( heightMeasureSpec != mImpl->mOldHeightMeasureSpec );
+
+  const bool isSpecExactly =
+    ( widthMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY ) &&
+    ( heightMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY );
+
+  const bool matchesSpecSize =
+    ( GetMeasuredWidth() == widthMeasureSpec.GetSize() ) &&
+    ( GetMeasuredHeight() == heightMeasureSpec.GetSize() );
+
+  const bool needsLayout = specChanged && ( !isSpecExactly || !matchesSpecSize );
+
+  if( forceLayout || needsLayout)
+  {
+    mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
+
+    //resolveRtlPropertiesIfNeeded();
+
+    int cacheIndex = -1;  // = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
+    if( cacheIndex < 0 ) //|| sIgnoreMeasureCache )
+    {
+      // measure ourselves, this should set the measured dimension flag back
+      OnMeasure( widthMeasureSpec, heightMeasureSpec );
+      mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
+    }
+    else
+    {
+      mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
+    }
+
+    // flag not set, setMeasuredDimension() was not invoked, we raise an exception to warn the developer
+    DALI_ASSERT_ALWAYS( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET ) &&
+                        "Layout's OnMeasure() did not set the measured dimension by calling setMeasuredDimension()" );
+    mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
+  }
+
+  mImpl->mOldWidthMeasureSpec = widthMeasureSpec;
+  mImpl->mOldHeightMeasureSpec = heightMeasureSpec;
+
+  //mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
+}
+
+void LayoutBase::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
+{
+  if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
+  {
+    OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
+    mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
+  }
+
+  bool changed = SetFrame( l, t, r, b );
+
+  if( changed || mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED ) )
+  {
+    OnLayout( changed, l, t, r, b );
+    mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
+  }
+
+  mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
+  mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_IS_LAID_OUT );
+}
+
+LayoutLength LayoutBase::GetMinimumWidth() const
+{
+  return mImpl->mMinimumSize.GetWidth();
+}
+
+LayoutLength LayoutBase::GetMinimumHeight() const
+{
+  return mImpl->mMinimumSize.GetHeight();
+}
+
+void LayoutBase::SetMinimumWidth( LayoutLength minimumWidth )
+{
+  mImpl->mMinimumSize.SetWidth( minimumWidth );
+  RequestLayout();
+}
+
+void LayoutBase::SetMinimumHeight( LayoutLength minimumHeight )
+{
+  mImpl->mMinimumSize.SetHeight( minimumHeight );
+  RequestLayout();
+}
+
+Extents LayoutBase::GetPadding() const
+{
+  return mImpl->mPadding;
+}
+
+LayoutLength LayoutBase::GetDefaultSize( LayoutLength size, MeasureSpec measureSpec )
+{
+  LayoutLength result = size;
+  auto specMode = measureSpec.GetMode();
+  auto specSize = measureSpec.GetSize();
+
+  switch (specMode)
+  {
+    case MeasureSpec::Mode::UNSPECIFIED:
+    {
+      result = size;
+      break;
+    }
+    case MeasureSpec::Mode::AT_MOST:
+    case MeasureSpec::Mode::EXACTLY:
+    {
+      result = specSize;
+      break;
+    }
+  }
+  return result;
+}
+
+void LayoutBase::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
+{
+  SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
+                         GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
+}
+
+void LayoutBase::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+}
+
+LayoutParent* LayoutBase::GetParent()
+{
+  return mImpl->mLayoutParent;
+}
+
+void LayoutBase::RequestLayout()
+{
+  // @todo Enforce failure if called in Measure/Layout passes.
+  mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
+  Toolkit::LayoutController layoutController = Toolkit::LayoutController::Get();
+  layoutController.RequestLayout( Toolkit::LayoutBase(this) );
+}
+
+bool LayoutBase::IsLayoutRequested() const
+{
+  return mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_FORCE_LAYOUT );
+}
+
+void LayoutBase::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
+{
+  mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET );
+  mImpl->mMeasuredWidth = measuredWidth;
+  mImpl->mMeasuredHeight = measuredHeight;
+}
+
+LayoutLength LayoutBase::GetMeasuredWidth() const
+{
+  // Get the size portion of the measured width
+  return  mImpl->mMeasuredWidth.GetSize();
+}
+
+LayoutLength LayoutBase::GetMeasuredHeight() const
+{
+  return  mImpl->mMeasuredHeight.GetSize();
+}
+
+MeasuredSize LayoutBase::GetMeasuredWidthAndState() const
+{
+  return mImpl->mMeasuredWidth;
+}
+
+MeasuredSize LayoutBase::GetMeasuredHeightAndState() const
+{
+  return mImpl->mMeasuredHeight;
+}
+
+LayoutLength LayoutBase::GetSuggestedMinimumWidth() const
+{
+  auto owner = GetOwner();
+  auto actor = Actor::DownCast(owner);
+  auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
+
+  return std::max( mImpl->mMinimumSize.GetWidth(), LayoutLength::IntType( naturalSize.width ) );
+}
+
+LayoutLength LayoutBase::GetSuggestedMinimumHeight() const
+{
+  auto owner = GetOwner();
+  auto actor = Actor::DownCast(owner);
+  auto naturalSize = actor ? actor.GetNaturalSize() : Vector3::ZERO;
+
+  return std::max( mImpl->mMinimumSize.GetHeight(), LayoutLength::IntType(naturalSize.height) );
+}
+
+MeasuredSize LayoutBase::ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec, MeasuredSize::State childMeasuredState )
+{
+  auto specMode = measureSpec.GetMode();
+  LayoutLength specSize = measureSpec.GetSize();
+  MeasuredSize result;
+
+  switch( specMode )
+  {
+    case MeasureSpec::Mode::AT_MOST:
+    {
+      if (specSize < size)
+      {
+        result = MeasuredSize( specSize, MeasuredSize::MEASURED_SIZE_TOO_SMALL );
+      }
+      else
+      {
+        result.SetSize( size );
+      }
+      break;
+    }
+
+    case MeasureSpec::Mode::EXACTLY:
+    {
+      result.SetSize( specSize );
+      break;
+    }
+
+    case MeasureSpec::Mode::UNSPECIFIED:
+    default:
+    {
+      result.SetSize( size );
+      break;
+    }
+  }
+
+  result.SetState( childMeasuredState );
+  return result;
+}
+
+
+bool LayoutBase::SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+  bool changed = false;
+
+  DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::SetFrame(%d, %d, %d, %d)\n", left.mValue, top.mValue, right.mValue, bottom.mValue );
+
+  if( mImpl->mLeft != left || mImpl->mRight != right || mImpl->mTop != top || mImpl->mBottom != bottom )
+  {
+    changed = true;
+
+    auto oldWidth = mImpl->mRight - mImpl->mLeft;
+    auto oldHeight = mImpl->mBottom - mImpl->mTop;
+    auto newWidth = right - left;
+    auto newHeight = bottom - top;
+    bool sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
+
+    mImpl->mLeft = left;
+    mImpl->mTop = top;
+    mImpl->mRight = right;
+    mImpl->mBottom = bottom;
+
+    mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_HAS_BOUNDS );
+
+
+    // Reflect up to parent control
+    auto owner = GetOwner();
+    auto actor = Actor::DownCast(owner);
+    if( actor )
+    {
+      if( mImpl->mAnimated )
+      {
+        auto animation = Animation::New( 0.5f );
+        animation.AnimateTo( Property( actor, Actor::Property::POSITION ),
+                             Vector3( float(left.mValue), float(top.mValue), 0.0f ) );
+        animation.AnimateTo( Property( actor, Actor::Property::SIZE ),
+                             Vector3( right-left, bottom-top, 0.0f ) );
+        animation.FinishedSignal().Connect( mSlotDelegate, &LayoutBase::OnLayoutAnimationFinished );
+        animation.Play();
+      }
+      else
+      {
+        // @todo Collate into list of Property & Property::Value pairs.
+        actor.SetPosition( Vector3( float(left.mValue), float(top.mValue), 0.0f ) );
+        actor.SetSize( Vector3( right-left, bottom-top, 0.0f ) );
+      }
+    }
+
+    if( sizeChanged )
+    {
+      SizeChange( LayoutSize( newWidth, newHeight ), LayoutSize( oldWidth, oldHeight ) );
+    }
+  }
+  return changed;
+}
+
+void LayoutBase::OnLayoutAnimationFinished( Animation& animation )
+{
+  auto owner = GetOwner();
+  auto actor = Actor::DownCast(owner);
+  if( actor )
+  {
+    actor.SetSize( Vector3( mImpl->mRight-mImpl->mLeft, mImpl->mBottom-mImpl->mTop, 0.0f ) );
+  }
+}
+
+void LayoutBase::SizeChange( LayoutSize newSize, LayoutSize oldSize)
+{
+  OnSizeChanged( newSize, oldSize );
+}
+
+
+void LayoutBase::OnSizeChanged( LayoutSize newSize, LayoutSize oldSize )
+{
+}
+
+void LayoutBase::OnInitialize()
+{
+}
+
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/layout-base-impl.h b/dali-toolkit/devel-api/layouting/layout-base-impl.h
new file mode 100644 (file)
index 0000000..835d2b1
--- /dev/null
@@ -0,0 +1,461 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_BASE_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_BASE_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 <memory>
+
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+#include <dali-toolkit/devel-api/layouting/child-layout-data.h>
+#include <dali-toolkit/devel-api/layouting/layout-base.h>
+#include <dali-toolkit/devel-api/layouting/layout-parent-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-controller.h>
+#include <dali-toolkit/devel-api/layouting/layout-size.h>
+#include <dali-toolkit/devel-api/layouting/measure-spec.h>
+#include <dali-toolkit/devel-api/layouting/measured-size.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class LayoutBase;
+using LayoutBasePtr = IntrusivePtr<LayoutBase>;
+
+
+/**
+ * Base class for layouts.
+ */
+class DALI_IMPORT_API LayoutBase : public BaseObject,
+                                   public LayoutParent
+{
+public:
+  /**
+   * Constructor.
+   */
+  LayoutBase();
+
+protected:
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  ~LayoutBase() = default;
+
+public:
+
+/**
+   * @brief Construct
+   *
+   * @param[in] owner The owner (container view / child view / visual ) of this layout
+   * @return a new LayoutBase object
+   */
+  static LayoutBasePtr New( Handle& owner );
+
+  /**
+   * @brief Remove the default copy constructor
+   */
+  LayoutBase(const LayoutBase& copy)=delete;
+
+  /**
+   * @brief Remove the default assignment operator
+   */
+  LayoutBase& operator=(const LayoutBase& rhs)=delete;
+
+  /**
+   * @brief Initialize the layout with it's owner and owner's type name
+   * @param[in] owner a handle to the owner container
+   * @param[in] containerType the type name of the owner container
+   */
+  void Initialize( Handle& owner, const std::string& containerType );
+
+  /**
+   * @brief Get a handle to the owner of this layout
+   *
+   * @return a handle to the owner of this layout
+   */
+  Handle GetOwner() const;
+
+  /**
+   * @brief Unparent this layout from it's owner, and remove any layout children in derived types
+   */
+  void Unparent();
+
+  /**
+   * @brief Set whether this layout should be animated or not
+   *
+   * @param[in] animateLayout True if the layout should be animated when applied
+   */
+  void SetAnimateLayout( bool animateLayout );
+
+  /**
+   * @brief Get whether this layout should be animated or not
+   *
+   * @return True if the layout should be animated when applied
+   */
+  bool IsLayoutAnimated() const;
+
+  /**
+   * @brief Register child properties of layout with owner type.
+   *
+   * The Actor hierarchy uses these registered properties in the type
+   * system to ensure child custom properties are properly initialized.
+   *
+   * @param[in] containerType The type of the containing view (owner)
+   */
+  void RegisterChildProperties( const std::string& containerType );
+
+  /**
+   * @brief  This is called to find out how big a layout should be.
+   *
+   * The parent supplies constraint information in the width and height parameters.
+   *
+   * The actual measurement work of a layout is performed in
+   * {@link #OnMeasure(MeasureSpec, MeasureSpec)}, called by this method. Therefore, only
+   * {@link #OnMeasure(MeasureSpec, MeasureSpec)} can and must be overridden by subclasses.
+   *
+   * @param[in] widthMeasureSpec Horizontal space requirements as imposed by the parent
+   * @param[in] heightMeasureSpec Vertical space requirements as imposed by the parent
+   *
+   * @see #OnMeasure(MeasureSpec, MeasureSpec)
+   */
+  void Measure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec );
+
+  /**
+   * @brief Assign a size and position to a layout and all of its descendants.
+   *
+   * This is the second phase of the layout mechanism.  (The first is measuring). In this phase, each parent
+   * calls layout on all of its children to position them.  This is typically done using the child
+   * measurements that were stored in the measure pass.
+   *
+   * Derived classes with children should override OnLayout. In that method, they should call Layout on each
+   * of their children.
+   *
+   * @param[in] left position, relative to parent
+   * @param[in] top position, relative to parent
+   * @param[in] right position, relative to parent
+   * @param[in] bottom position, relative to parent
+   */
+  void Layout( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom );
+
+  /**
+   * @brief Utility to return a default size.
+   *
+   * Uses the supplied size if the MeasureSpec imposed no constraints. Will get larger if allowed by the
+   * MeasureSpec.
+   *
+   * @param[in] size Default size for this layout
+   * @param[in] measureSpec Constraints imposed by the parent
+   * @return The size this layout should be.
+   */
+  static LayoutLength GetDefaultSize( LayoutLength size, MeasureSpec measureSpec );
+
+  /**
+   * @copydoc LayoutParent::GetParent
+   */
+  virtual LayoutParent* GetParent() override;
+
+  /**
+   * @brief Request that this layout is re-laid out.
+   *
+   * This will make this layout and all it's parent layouts dirty.
+   */
+  void RequestLayout();
+
+  /**
+   * @brief Predicate to determine if this layout has been requested to re-layout
+   *
+   * @return True if a layout request has occured on this layout
+   */
+  bool IsLayoutRequested() const;
+
+  /**
+   * @brief Get the measured width (without any measurement flags).
+   *
+   * This method should be used only during measurement and layout calculations.
+   *
+   * Use {@link Dali::Actor::GetTargetSize()} to see how wide a control is after layout
+   */
+  LayoutLength GetMeasuredWidth() const;
+
+  /**
+   * @brief Get the measured height (without any measurement flags).
+   *
+   * This method should be used only during measurement and layout calculations.
+   *
+   * Use {@link Dali::Actor::GetTargetSize()} to see how high a control is after layout
+   */
+  LayoutLength GetMeasuredHeight() const;
+
+  /**
+   * @brief Get the measured width and state.
+   *
+   * This method should be used only during measurement and layout calculations.
+   *
+   * Use {@link Dali::Actor::GetTargetSize()} to see how wide a view is after layout
+   */
+  MeasuredSize GetMeasuredWidthAndState() const;
+
+  /**
+   * @brief Get the measured height and state.
+   *
+   * This method should be used only during measurement and layout calculations.
+   *
+   * Use {@link Dali::Actor::GetTargetSize()} to see how high a view is after layout
+   */
+  MeasuredSize GetMeasuredHeightAndState() const;
+
+  /**
+   * @brief Returns the suggested minimum width that the layout should use.
+   *
+   * This returns the maximum of the layout's minimum width and the background's minimum width
+   *
+   * When being used in {@link #OnMeasure()}, the caller should still
+   * ensure the returned width is within the requirements of the parent.
+   *
+   * @return The suggested minimum width of the layout.
+   */
+  LayoutLength GetSuggestedMinimumWidth() const;
+
+  /**
+   * @brief Returns the suggested minimum height that the layout should use.
+   *
+   * This returns the maximum of the layout's minimum height and the background's minimum height
+   *
+   * When being used in {@link #OnMeasure()}, the caller should still
+   * ensure the returned height is within the requirements of the parent.
+   *
+   * @return The suggested minimum height of the layout.
+   */
+  LayoutLength GetSuggestedMinimumHeight() const;
+
+  /**
+   * @brief Sets the minimum width of the layout.
+   *
+   * It is not guaranteed the layout will be able to achieve this minimum width (for example, if its parent
+   * layout constrains it with less available width).
+   *
+   * @param[in] minWidth The minimum width the layout will try to be, in pixels
+   *
+   * @see #GetMinimumWidth()
+   */
+  void SetMinimumWidth( LayoutLength minWidth );
+
+  /**
+   * @brief Sets the minimum height of the layout.
+   *
+   * It is not guaranteed the layout will be able to achieve this minimum height (for example, if its parent
+   * layout constrains it with less available height).
+   *
+   * @param[in] minHeight The minimum height the layout will try to be, in pixels
+   *
+   * @see #GetMinimumHeight()
+   */
+  void SetMinimumHeight( LayoutLength minHeight );
+
+  /**
+   * @brief Returns the minimum width of the layout.
+   *
+   * @return the minimum width the layout will try to be, in pixels
+   *
+   * @see #SetMinimumWidth(LayoutLength)
+   */
+  LayoutLength GetMinimumWidth() const;
+
+  /**
+   * @brief Returns the minimum height of the layout.
+   *
+   * @return the minimum height the layout will try to be, in pixels
+   *
+   * @see #SetMinimumHeight(LayoutLength)
+   */
+  LayoutLength GetMinimumHeight() const;
+
+  /**
+   * Get the padding information
+   * @return The padding information
+   */
+  Extents GetPadding() const;
+
+protected:
+  /**
+   * @brief Allow directly deriving classes to remove layout children when unparented
+   */
+  virtual void OnUnparent(){};
+
+  /**
+   * @brief Ensure direct derived types register their child properties with the owner
+   *
+   * @param[in] containerType The type name of the owner container
+   */
+  virtual void OnRegisterChildProperties( const std::string& containerType );
+
+
+  /**
+   * @brief Measure the layout and its content to determine the measured width and the
+   * measured height.
+   *
+   * This method is invoked by {@link #Measure(MeasureSpec, MeasureSpec)} and
+   * should be overridden by subclasses to provide accurate and efficient
+   * measurement of their contents.
+   *
+   * <strong>CONTRACT:</strong> When overriding this method, you
+   * <em>must</em> call {@link #SetMeasuredDimensions(MeasuredSize,MeasuredSize)} to store the
+   * measured width and height of this layout. Failure to do so will trigger an
+   * <code>IllegalStateException</code>, thrown by
+   * {@link #Measure(MeasureSpec,MeasureSpec)}. Calling the superclass'
+   * {@link #OnMeasure(MeasureSpec,MeasureSpec)} is a valid use.
+   *
+   * The base class implementation of measure defaults to the background size,
+   * unless a larger size is allowed by the MeasureSpec. Subclasses should
+   * override {@link #OnMeasure(MeasureSpec,MeasureSpec)} to provide better measurements of
+   * their content.
+   *
+   * If this method is overridden, it is the subclass's responsibility to make
+   * sure the measured height and width are at least the layout's minimum height
+   * and width ({@link #GetSuggestedMinimumHeight()} and
+   * {@link #GetSuggestedMinimumWidth()}).
+   *
+   * @param[in] widthMeasureSpec horizontal space requirements as imposed by the parent.
+   *                             The requirements are encoded with
+   *                             {@link MeasureSpec}.
+   * @param[in] heightMeasureSpec vertical space requirements as imposed by the parent.
+   *                              The requirements are encoded with
+   *                              {@link MeasureSpec}.
+   *
+   * @see #GetMeasuredWidth()
+   * @see #GetMeasuredHeight()
+   * @see #GetSuggestedMinimumHeight()
+   * @see #GetSuggestedMinimumWidth()
+   * @see MeasureSpec#GetMode(int)
+   * @see MeasureSpec#GetSize(int)
+   */
+  virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec );
+
+  /**
+   * @brief Called from Layout() when this layout should assign a size and position to each of its children.
+   *
+   * Derived classes with children should override this method and call Layout() on each of their children.
+   *
+   * @param[in] changed This is a new size or position for this layout
+   * @param[in] left Left position, relative to parent
+   * @param[in] top Top position, relative to parent
+   * @param[in] right Right position, relative to parent
+   * @param[in] bottom Bottom position, relative to parent
+   */
+  virtual void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom );
+
+
+  /**
+   * @brief This method must be called by {@link #OnMeasure(MeasureSpec,MeasureSpec)} to store the
+   * measured width and measured height.
+   *
+   * Failing to do so will trigger an exception at measurement time.
+   *
+   * @param[in] measuredWidth The measured width of this layout. This may have a state of
+   * {@link MeasuredSize::MEASURED_SIZE_TOO_SMALL}
+   *
+   * @param[in] measuredHeight The measured height of this layout. This may have a state of
+   * {@link MeasuredSize::MEASURED_SIZE_TOO_SMALL}
+   */
+  void SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight );
+
+  /**
+   * @brief Utility to reconcile a desired size and state, with constraints imposed by a MeasureSpec.
+   *
+   * @param[in] size How big the layout wants to be.
+   * @param[in] measureSpec Constraints imposed by the parent.
+   * @param[in] childMeasuredState Size information bit mask for the layout's children.
+   *
+   * @return A measured size, which may indicate that it is too small.
+   */
+  static MeasuredSize ResolveSizeAndState( LayoutLength size, MeasureSpec measureSpec,
+                                           MeasuredSize::State childMeasuredState );
+
+  /**
+   * @brief Sets the frame (the size and position) of the layout onto it's owner
+   *
+   * @todo Consider instead, collating properties into LayoutCollector in order to set/animate them all
+   * in one block.
+   * @param[in] left The horizontal position of the left edge of this frame within the parent layout
+   * @param[in] top The vertical position of the top edge of this frame within the parent layout
+   * @param[in] right The horizontal position of the right edge of this frame within the parent layout
+   * @param[in] bottom The vertical position of the bottom edge of this frame within the parent layout
+   */
+  bool SetFrame( LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom );
+
+  /**
+   * Virtual method to inform derived classes when the layout size changed
+   * @param[in] newSize The new size of the layout
+   * @param[in] oldSize The old size of the layout
+   */
+  virtual void OnSizeChanged( LayoutSize newSize, LayoutSize oldSize );
+
+
+  /**
+   * @brief Initialization method for LayoutGroup to override
+   */
+  virtual void OnInitialize();
+
+private:
+  /**
+   * @brief Called to change the size of the layout.
+   *
+   * @param[in] newSize The new size of the layout
+   * @param[in] oldSize The old size of the layout
+   */
+  void SizeChange( LayoutSize newSize, LayoutSize oldSize );
+
+  /**
+   * @brief Triggered when a layout animation finished.
+   *
+   * @param[in] animation  A handle to the layout animation
+   */
+  void OnLayoutAnimationFinished( Animation& animation );
+
+public:
+  class Impl; // Class declaration is public so we can add devel API's in the future
+
+
+private:
+  std::unique_ptr<Impl> mImpl; ///< Implementation class holds all the data
+  SlotDelegate<LayoutBase> mSlotDelegate;
+};
+
+} //namespace Internal
+
+inline Internal::LayoutBase& GetImplementation( Dali::Toolkit::LayoutBase& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "LayoutBase handle is empty" );
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast< Internal::LayoutBase& >( object );
+}
+
+inline const Internal::LayoutBase& GetImplementation( const Dali::Toolkit::LayoutBase& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "LayoutBase handle is empty" );
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast< const Internal::LayoutBase& >( object );
+}
+
+} //namespace Toolkit
+} //namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_BASE_H
diff --git a/dali-toolkit/devel-api/layouting/layout-base.cpp b/dali-toolkit/devel-api/layouting/layout-base.cpp
new file mode 100644 (file)
index 0000000..07aa595
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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-toolkit/devel-api/layouting/layout-base.h>
+#include <dali-toolkit/devel-api/layouting/layout-base-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+LayoutBase::LayoutBase()
+: BaseHandle()
+{
+}
+
+LayoutBase LayoutBase::New( Handle& handle )
+{
+  Internal::LayoutBasePtr layout = Internal::LayoutBase::New( handle );
+  return LayoutBase( layout.Get() );
+}
+
+LayoutBase::LayoutBase( Internal::LayoutBase* layoutBase )
+: BaseHandle( layoutBase )
+{
+}
+
+Handle LayoutBase::GetOwner() const
+{
+  return GetImplementation( *this ).GetOwner();
+}
+
+void LayoutBase::SetAnimateLayout( bool animateLayout )
+{
+  GetImplementation( *this ).SetAnimateLayout( animateLayout );
+}
+
+bool LayoutBase::IsLayoutAnimated() const
+{
+  return GetImplementation( *this ).IsLayoutAnimated();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/layout-base.h b/dali-toolkit/devel-api/layouting/layout-base.h
new file mode 100644 (file)
index 0000000..8686f53
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_LAYOUT_BASE_H
+#define DALI_TOOLKIT_LAYOUTING_LAYOUT_BASE_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 <memory>
+#include <cstdint>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/object/property-index-ranges.h>
+#include <dali-toolkit/devel-api/layouting/child-layout-data.h>
+#include <dali-toolkit/devel-api/layouting/measure-spec.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Internal
+{
+class LayoutBase;
+}
+
+using LayoutId = unsigned int;
+
+
+/**
+ * Base class for layouts. It is used to layout a control (or visual).
+ * It can be laid out by a LayoutGroup.
+ */
+class DALI_IMPORT_API LayoutBase : public BaseHandle
+{
+public:
+
+  enum PropertyRange
+  {
+    CHILD_PROPERTY_START_INDEX = CHILD_PROPERTY_REGISTRATION_START_INDEX, ///< Start index is used by child properties
+    CHILD_PROPERTY_END_INDEX   = CHILD_PROPERTY_REGISTRATION_START_INDEX+1000 ///< Reserving 1000 property indices
+  };
+
+  struct ChildProperty
+  {
+    enum
+    {
+      WIDTH_SPECIFICATION = ///< Child property to specify desired width (May use MATCH_PARENT/WRAP_CONTENT)
+        CHILD_PROPERTY_START_INDEX,
+      HEIGHT_SPECIFICATION ///< Child property to specify desired height (May use MATCH_PARENT/WRAP_CONTENT)
+    };
+  };
+
+  /**
+   * @brief Default constructor which provides an uninitialized Dali::LayoutBase.
+   */
+  LayoutBase();
+
+  /**
+   * @brief Default destructor
+   */
+  ~LayoutBase()=default;
+
+  /**
+   * @brief Create an initialized LayoutBase
+   *
+   * @param[in] handle A handle to the object that this layout for, e.g. a Control or a Visual::Base
+   * @warning This is an interim function, and will be deleted when all controls have layouts
+   * @todo Ensure that this warning is implemented
+   */
+  static LayoutBase New( Handle& handle );
+
+  /**
+   * @brief Copy constructor
+   * @param[in] copy The LayoutBase to copy.
+   */
+  LayoutBase(const LayoutBase& copy) = default;
+
+  /**
+   * @brief Assignment operator
+   * @param[in] rhs The LayoutBase to copy
+   */
+  LayoutBase& operator=( const LayoutBase& rhs ) = default;
+
+  /**
+   * @brief Get a handle to the control or visual this layout represents.
+   *
+   * @return
+   */
+  Handle GetOwner() const;
+
+  /**
+   * @brief Set whether this layout should be animated or not
+   *
+   * @param[in] animateLayout True if the layout should be animated when applied
+   */
+  void SetAnimateLayout( bool animateLayout );
+
+  /**
+   * @brief Predicate to determine whether this layout should be animated when applied
+   *
+   * @return True if the layout should be animated when applied
+   */
+  bool IsLayoutAnimated() const;
+
+public:
+  /// @cond internal
+  /**
+   * @brief This constructor is used by LayoutBase::New() methods.
+   *
+   * @param[in] actor A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL LayoutBase( Internal::LayoutBase* layoutBase );
+  /// @endcond
+};
+
+
+}//namespace Toolkit
+}//namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_LAYOUT_BASE_H
diff --git a/dali-toolkit/devel-api/layouting/layout-controller.cpp b/dali-toolkit/devel-api/layouting/layout-controller.cpp
new file mode 100644 (file)
index 0000000..7c1b402
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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/layout-controller.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/layouting/layout-controller-impl.h>
+
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+LayoutController::LayoutController()
+{
+}
+
+LayoutController::~LayoutController()
+{
+}
+
+LayoutController LayoutController::Get()
+{
+  LayoutController layoutController;
+
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    Dali::BaseHandle handle = singletonService.GetSingleton( typeid(LayoutController) );
+    if( handle )
+    {
+      // If so, downcast the handle of singleton to layout controller
+      layoutController = LayoutController( dynamic_cast<Internal::LayoutController*>( handle.GetObjectPtr() ) );
+    }
+
+    if( !layoutController )
+    {
+      // If not, create the layout controller and register it as a singleton
+      Internal::LayoutController* impl = new Internal::LayoutController();
+      layoutController = LayoutController( impl );
+      impl->Initialize();
+
+      // Registering the singleton will automatically register the processor with Core.
+      singletonService.Register( typeid(layoutController), layoutController );
+    }
+  }
+
+  return layoutController;
+}
+
+void LayoutController::RequestLayout( LayoutBase layout )
+{
+  GetImpl(*this).RequestLayout( GetImplementation( layout ) );
+}
+
+LayoutController::LayoutController( Internal::LayoutController *impl )
+: BaseHandle( impl )
+{
+}
+
+} //namespace Toolkit
+} //namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/layout-controller.h b/dali-toolkit/devel-api/layouting/layout-controller.h
new file mode 100644 (file)
index 0000000..96d44f0
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef DALI_TOOLKIT_DEVEL_LAYOUT_CONTROLLER_H
+#define DALI_TOOLKIT_DEVEL_LAYOUT_CONTROLLER_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/object/base-handle.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/layouting/layout-base.h>
+#include <dali-toolkit/devel-api/layouting/layout-group.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Internal
+{
+class LayoutController;
+}
+
+/**
+ * @brief Controls the process of layouting the control tree. It provides methods to enable
+ * controls to re-layout and internal systems to separately measure and layout controls.
+ */
+class DALI_IMPORT_API LayoutController : public BaseHandle
+{
+public:
+  /**
+   * @brief Constructor - create an uninitialized handle.
+   *
+   * This can be initialized with LayoutController::Get().
+   * Calling member functions with an uninitialized handle is not allowed.
+   */
+  LayoutController();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~LayoutController();
+
+  /**
+   * @brief Gets the singleton of the LayoutController object.
+   *
+   * @return A handle to the LayoutController object.
+   */
+  static LayoutController Get();
+
+  /**
+   * @brief Request for a particular layout (wrapping a control or a visual) to be measured and laid out.
+   * @param[in] layout The layout to measure & relayout.
+   */
+  void RequestLayout( LayoutBase layout );
+
+public:
+  /// @cond internal
+  /**
+   * @brief This constructor is used by LayoutController::New() methods.
+   *
+   * @param[in] actor A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL LayoutController( Internal::LayoutController *impl );
+  /// @endcond
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_LAYOUT_CONTROLLER_H
diff --git a/dali-toolkit/devel-api/layouting/layout-group-impl.cpp b/dali-toolkit/devel-api/layouting/layout-group-impl.cpp
new file mode 100644 (file)
index 0000000..844e35a
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * 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/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali-toolkit/internal/layouting/layout-group-data-impl.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+
+namespace
+{
+const char* MARGIN_SPECIFICATION_NAME( "marginSpec" );
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+LayoutGroup::LayoutGroup()
+: mImpl( new LayoutGroup::Impl() ),
+  mSlotDelegate(this)
+{
+}
+
+LayoutGroup::~LayoutGroup()
+{
+}
+
+Toolkit::LayoutGroup::LayoutId LayoutGroup::Add( LayoutBase& child )
+{
+  LayoutParent* oldParent = child.GetParent();
+  if( oldParent )
+  {
+    LayoutGroupPtr parentGroup( dynamic_cast< LayoutGroup* >( oldParent ) );
+    if( parentGroup )
+    {
+      parentGroup->Remove( child );
+    }
+  }
+
+  Impl::ChildLayout childLayout;
+  childLayout.layoutId = mImpl->mNextLayoutId++;
+  childLayout.child = &child;
+  mImpl->mChildren.emplace_back( childLayout );
+
+  auto owner = child.GetOwner();
+
+  // If the owner does not have any LayoutBase child properties, add them
+  if( ! DevelHandle::DoesCustomPropertyExist( owner, Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION ) )
+  {
+    // Set default properties for LayoutGroup and LayoutBase.
+    // Deriving classes can override OnChildAdd() to add their own default properties
+    GenerateDefaultChildPropertyValues( owner );
+  }
+
+  // Inform deriving classes that this child has been added
+  OnChildAdd( *childLayout.child.Get() );
+
+  // Now listen to future changes to the child properties.
+  DevelHandle::PropertySetSignal(owner).Connect( this, &LayoutGroup::OnSetChildProperties );
+
+  RequestLayout();
+
+  return childLayout.layoutId;
+}
+
+void LayoutGroup::Remove( Toolkit::LayoutGroup::LayoutId childId )
+{
+  for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter )
+  {
+    if( iter->layoutId == childId )
+    {
+      OnChildRemove( *iter->child.Get() );
+      mImpl->mChildren.erase(iter);
+      break;
+    }
+  }
+  RequestLayout();
+}
+
+void LayoutGroup::Remove( LayoutBase& child )
+{
+  for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter )
+  {
+    if( iter->child.Get() == &child )
+    {
+      OnChildRemove( *iter->child.Get() );
+      mImpl->mChildren.erase(iter);
+      break;
+    }
+  }
+  RequestLayout();
+}
+
+void LayoutGroup::RemoveAll()
+{
+  for( auto iter = mImpl->mChildren.begin() ; iter != mImpl->mChildren.end() ; ++iter )
+  {
+    OnChildRemove( *iter->child.Get() );
+    iter = mImpl->mChildren.erase(iter);
+  }
+}
+
+unsigned int LayoutGroup::GetChildCount() const
+{
+  return mImpl->mChildren.size();
+}
+
+LayoutBasePtr LayoutGroup::GetChildAt( unsigned int index ) const
+{
+  DALI_ASSERT_ALWAYS( index < mImpl->mChildren.size() );
+  return mImpl->mChildren[ index ].child;
+}
+
+LayoutBasePtr LayoutGroup::GetChild( Toolkit::LayoutGroup::LayoutId childId ) const
+{
+  for( auto&& childLayout : mImpl->mChildren )
+  {
+    if( childLayout.layoutId == childId )
+    {
+      return childLayout.child;
+    }
+  }
+  return NULL;
+}
+
+Toolkit::LayoutGroup::LayoutId LayoutGroup::GetChildId( LayoutBase& child ) const
+{
+  for( auto&& childLayout : mImpl->mChildren )
+  {
+    if( childLayout.child.Get() == &child )
+    {
+      return childLayout.layoutId;
+    }
+  }
+  return Toolkit::LayoutGroup::UNKNOWN_ID;
+}
+
+void LayoutGroup::OnChildAdd( LayoutBase& child )
+{
+}
+
+void LayoutGroup::OnChildRemove( LayoutBase& child )
+{
+}
+
+void LayoutGroup::DoInitialize()
+{
+}
+
+void LayoutGroup::DoRegisterChildProperties( const std::string& containerType )
+{
+}
+
+void LayoutGroup::OnSetChildProperties( Handle& handle, Property::Index index, Property::Value value )
+{
+  if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
+  {
+    // If any child properties are set, must perform relayout
+    RequestLayout();
+  }
+}
+
+void LayoutGroup::GenerateDefaultChildPropertyValues( Handle child )
+{
+  child.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION,
+                     Toolkit::ChildLayoutData::WRAP_CONTENT );
+  child.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION,
+                     Toolkit::ChildLayoutData::WRAP_CONTENT );
+  child.SetProperty( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Extents() );
+}
+
+void LayoutGroup::MeasureChildren( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
+{
+  for( auto&& child : mImpl->mChildren )
+  {
+    //if( (child.mViewFlags & Impl::VISIBILITY_MASK) != Impl::GONE ) // Use owner visibility/enabled/ready
+    {
+      MeasureChild( child.child, widthMeasureSpec, heightMeasureSpec );
+    }
+  }
+}
+
+void LayoutGroup::MeasureChild( LayoutBasePtr child,
+                                MeasureSpec parentWidthMeasureSpec,
+                                MeasureSpec parentHeightMeasureSpec )
+{
+  auto childOwner = child->GetOwner();
+  auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
+  auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
+
+  auto padding = GetPadding();
+
+  const MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( parentWidthMeasureSpec,
+                                                                 padding.start + padding.end,
+                                                                 desiredWidth);
+  const MeasureSpec childHeightMeasureSpec = GetChildMeasureSpec( parentHeightMeasureSpec,
+                                                                  padding.top + padding.bottom,
+                                                                  desiredHeight);
+
+  child->Measure( childWidthMeasureSpec, childHeightMeasureSpec );
+}
+
+void LayoutGroup::MeasureChildWithMargins( LayoutBasePtr child,
+                                           MeasureSpec parentWidthMeasureSpec, LayoutLength widthUsed,
+                                           MeasureSpec parentHeightMeasureSpec, LayoutLength heightUsed)
+{
+  auto childOwner = child->GetOwner();
+  auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
+  auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
+  auto desiredMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
+  auto padding = GetPadding();
+
+  MeasureSpec childWidthMeasureSpec = GetChildMeasureSpec( parentWidthMeasureSpec,
+                                                           padding.start + padding.end +
+                                                           desiredMargin.start + desiredMargin.end +
+                                                           widthUsed, desiredWidth );
+
+  MeasureSpec childHeightMeasureSpec = GetChildMeasureSpec( parentHeightMeasureSpec,
+                                                            padding.top + padding.bottom +
+                                                            desiredMargin.top + desiredMargin.end +
+                                                            heightUsed, desiredHeight );
+
+  child->Measure( childWidthMeasureSpec, childHeightMeasureSpec );
+}
+
+
+MeasureSpec LayoutGroup::GetChildMeasureSpec(
+  MeasureSpec  measureSpec,
+  LayoutLength padding,
+  LayoutLength childDimension )
+{
+  auto specMode = measureSpec.GetMode();
+  LayoutLength specSize = measureSpec.GetSize();
+
+  auto size = std::max( LayoutLength(0), specSize - padding );
+
+  MeasureSpec::IntType resultSize = 0;
+  MeasureSpec::Mode resultMode = MeasureSpec::Mode::UNSPECIFIED;
+
+  switch( specMode )
+  {
+    // Parent has imposed an exact size on us
+    case MeasureSpec::Mode::EXACTLY:
+    {
+
+      if (childDimension == Toolkit::ChildLayoutData::MATCH_PARENT)
+      {
+        // Child wants to be our size. So be it.
+        resultSize = size;
+        resultMode = MeasureSpec::Mode::EXACTLY;
+      }
+      else if (childDimension == Toolkit::ChildLayoutData::WRAP_CONTENT)
+      {
+        // Child wants to determine its own size. It can't be
+        // bigger than us.
+        resultSize = size;
+        resultMode = MeasureSpec::Mode::AT_MOST;
+      }
+      else
+      {
+        resultSize = childDimension;
+        resultMode = MeasureSpec::Mode::EXACTLY;
+      }
+
+      break;
+    }
+
+      // Parent has imposed a maximum size on us
+    case MeasureSpec::Mode::AT_MOST:
+    {
+      if (childDimension == Toolkit::ChildLayoutData::MATCH_PARENT)
+      {
+        // Child wants to be our size, but our size is not fixed.
+        // Constrain child to not be bigger than us.
+        resultSize = size;
+        resultMode = MeasureSpec::Mode::AT_MOST;
+      }
+      else if (childDimension == Toolkit::ChildLayoutData::WRAP_CONTENT)
+      {
+        // Child wants to determine its own size. It can't be
+        // bigger than us.
+        resultSize = size;
+        resultMode = MeasureSpec::Mode::AT_MOST;
+      }
+      else
+      {
+        // Child wants a specific size... so be it
+        resultSize = childDimension;
+        resultMode = MeasureSpec::Mode::EXACTLY;
+      }
+
+      break;
+    }
+
+      // Parent asked to see how big we want to be
+    case MeasureSpec::Mode::UNSPECIFIED:
+    {
+      if (childDimension == Toolkit::ChildLayoutData::MATCH_PARENT)
+      {
+        // Child wants to be our size... find out how big it should be
+        resultSize = LayoutBase::Impl::sUseZeroUnspecifiedMeasureSpec ? LayoutLength(0) : size;
+        resultMode = MeasureSpec::Mode::UNSPECIFIED;
+      }
+      else if (childDimension == Toolkit::ChildLayoutData::WRAP_CONTENT)
+      {
+        // Child wants to determine its own size.... find out how big
+        // it should be
+        resultSize = LayoutBase::Impl::sUseZeroUnspecifiedMeasureSpec ? LayoutLength(0) : size;
+        resultMode = MeasureSpec::Mode::UNSPECIFIED;
+      }
+      else
+      {
+        // Child wants a specific size... let him have it
+        resultSize = childDimension;
+        resultMode = MeasureSpec::Mode::EXACTLY;
+      }
+      break;
+    }
+  }
+
+  //noinspection ResourceType
+  return MeasureSpec( resultSize, resultMode );
+}
+
+
+void LayoutGroup::OnInitialize()
+{
+  auto control = Toolkit::Control::DownCast( GetOwner() );
+
+  if( control )
+  {
+    // Take ownership of existing children
+    for( unsigned int childIndex = 0 ; childIndex < control.GetChildCount(); ++childIndex )
+    {
+      ChildAddedToOwner( control.GetChildAt( childIndex ) );
+    }
+
+    DevelActor::ChildAddedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildAddedToOwner );
+    DevelActor::ChildRemovedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildRemovedFromOwner );
+    DevelHandle::PropertySetSignal( control ).Connect( mSlotDelegate, &LayoutGroup::OnOwnerPropertySet );
+  }
+}
+
+void LayoutGroup::OnRegisterChildProperties( const std::string& containerType )
+{
+  auto typeInfo = TypeRegistry::Get().GetTypeInfo( containerType );
+  if( typeInfo )
+  {
+    Property::IndexContainer indices;
+    typeInfo.GetChildPropertyIndices( indices );
+
+    if( std::find( indices.Begin(), indices.End(), Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION ) ==
+        indices.End() )
+    {
+      ChildPropertyRegistration( typeInfo.GetName(), MARGIN_SPECIFICATION_NAME, Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Property::EXTENTS );
+    }
+  }
+
+  DoRegisterChildProperties( containerType );
+}
+
+void LayoutGroup::OnUnparent()
+{
+  RemoveAll();
+}
+
+void LayoutGroup::ChildAddedToOwner( Actor child )
+{
+  LayoutBasePtr childLayout;
+  Toolkit::Control control = Toolkit::Control::DownCast( child );
+
+  if( control ) // Can only support adding Controls, not Actors to layout
+  {
+    Internal::Control& childControlImpl = GetImplementation( control );
+    Internal::Control::Impl& childControlDataImpl = Internal::Control::Impl::Get( childControlImpl );
+    childLayout = childControlDataImpl.GetLayout();
+
+    if( ! childLayout )
+    {
+      // If the child doesn't already have a layout, then create a LayoutBase for it.
+      childLayout = LayoutBase::New( control );
+      childLayout->SetAnimateLayout( IsLayoutAnimated() ); // @todo this essentially forces animation inheritance. Bad?
+
+      auto desiredSize = control.GetNaturalSize();
+      childControlDataImpl.SetLayout( *childLayout.Get() );
+
+      // HBoxLayout will apply default layout data for this object
+      child.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, LayoutLength::IntType( desiredSize.width ) );
+      child.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, LayoutLength::IntType( desiredSize.height ) );
+      child.SetProperty( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION, Extents() );
+    }
+
+    Add( *childLayout.Get() );
+  }
+}
+
+void LayoutGroup::ChildRemovedFromOwner( Actor child )
+{
+  Toolkit::Control control = Toolkit::Control::DownCast( child );
+  if( control )
+  {
+    Internal::Control& childControlImpl = GetImplementation( control );
+    Internal::Control::Impl& childControlDataImpl = Internal::Control::Impl::Get( childControlImpl );
+    auto childLayout = childControlDataImpl.GetLayout();
+    if( childLayout )
+    {
+      Remove( *childLayout.Get() );
+    }
+  }
+}
+
+void LayoutGroup::OnOwnerPropertySet( Handle& handle, Property::Index index, Property::Value value )
+{
+  auto actor = Actor::DownCast( handle );
+  if( actor && index == Actor::Property::LAYOUT_DIRECTION )
+  {
+    RequestLayout();
+  }
+}
+
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/layout-group-impl.h b/dali-toolkit/devel-api/layouting/layout-group-impl.h
new file mode 100644 (file)
index 0000000..d84495b
--- /dev/null
@@ -0,0 +1,297 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_GROUP_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_GROUP_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 <memory>
+
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali-toolkit/devel-api/layouting/child-layout-data.h>
+#include <dali-toolkit/devel-api/layouting/layout-group.h>
+#include <dali-toolkit/devel-api/layouting/layout-base-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class LayoutGroup;
+using LayoutGroupPtr = IntrusivePtr<LayoutGroup>;
+
+/**
+ * LayoutGroup is an abstract class that provides child layout management and basic measuring and layouting.
+ *
+ * Deriving classes should override LayoutBase::DoInitialize for second stage initialization,
+ * LayoutGroup::DoRegisterChildProperties to register child property types with the owner,
+ * LayoutGroup::OnChildAdd to apply default child property values to the child.
+ * Deriving classes may override LayoutGroup::OnChildRemove.
+ *
+ * Deriving classes must also override OnMeasure and OnLayout as follows:
+ *
+ * OnMeasure should measure each child using LayoutGroup::MeasureChildWithMargins or LayoutGroup::MeasureChild.
+ * We recommend calling LayoutBase::ResolveSizeAndState() to resolve measure specs.
+ * If some children don't fit, then they can be measured again with different MeasureSpecs as required.
+ *
+ * After measurement, the derived class must also call SetMeasuredDimensions to set it's own requested size.
+ *
+ * OnLayout should use it's own layout parameters and the measured children's size to determine the children's
+ * position and size; it should then call Layout() on the child layout to layout the child and it's hierarchy.
+ */
+class DALI_IMPORT_API LayoutGroup : public LayoutBase,
+                                    public ConnectionTracker
+{
+public:
+  /**
+   * Constructor. Returns an initialized object
+   */
+  LayoutGroup();
+
+protected:
+  /**
+   * Virtual destructor may only be called by Unreference()
+   */
+  virtual ~LayoutGroup();
+
+public:
+  LayoutGroup( const LayoutGroup& copy ) = delete;
+  LayoutGroup& operator=( const LayoutGroup& rhs ) = delete;
+
+  /**
+   * @brief Add a layout child to this group.
+   *
+   * @param[in] layoutChild The child to add
+   * @return The layout id of this child.
+   */
+  Toolkit::LayoutGroup::LayoutId Add( LayoutBase& layoutChild );
+
+  /**
+   * @brief Remove a layout child from this group.
+   * @param[in] childId The layout child id
+   */
+  void Remove( Toolkit::LayoutGroup::LayoutId childId );
+
+  /**
+   * @brief Remove a layout child from this group
+   * @param[in] child The layout child
+   */
+  void Remove( LayoutBase& child );
+
+  /**
+   * @brief Remove all layout children.
+   *
+   * @note This will not unparent owner's children
+   */
+  void RemoveAll();
+
+
+  /**
+   * @brief Get the number of children contained by this layout group
+   *
+   * @return the number of children
+   */
+  unsigned int GetChildCount() const;
+
+  /**
+   * Get the child layout at the given index
+   */
+  LayoutBasePtr GetChildAt( unsigned int childIndex ) const;
+
+  /**
+   * Get the child layout id of the given child
+   */
+  Toolkit::LayoutGroup::LayoutId GetChildId( LayoutBase& child ) const;
+
+  /**
+   * @brief Get the layout child with the given layout id.
+   * @note child id's start at 1, and follow the insertion order
+   * @param[in] childId the layout id of the child within this group
+   * @return A pointer to the child layout
+   */
+  LayoutBasePtr GetChild( Toolkit::LayoutGroup::LayoutId childId ) const;
+
+  template <typename T>
+    LayoutBasePtr GetChild( T childId ) = delete; // Prevent implicit casting of int/uint to LayoutId
+
+  /**
+   * Callback when child is added to container.
+   * Derived classes can use this to set their own child properties on the child layout's owner.
+   */
+  virtual void OnChildAdd( LayoutBase& child );
+
+  /**
+   * Callback when child is removed from container.
+   */
+  virtual void OnChildRemove( LayoutBase& child );
+
+  /**
+   * @brief Calculate the right measure spec for this child.
+   *
+   * Does the hard part of MeasureChildren: figuring out the MeasureSpec to
+   * pass to a particular child. This method figures out the right MeasureSpec
+   * for one dimension (height or width) of one child view.
+   *
+   * The goal is to combine information from our MeasureSpec with the
+   * LayoutParams of the child to get the best possible results. For example,
+   * if the this view knows its size (because its MeasureSpec has a mode of
+   * EXACTLY), and the child has indicated in its LayoutParams that it wants
+   * to be the same size as the parent, the parent should ask the child to
+   * layout given an exact size.
+   *
+   * @param measureSpec The requirements for this view
+   *
+   * @param padding The padding of this view for the current dimension
+   *        and margins, if applicable
+   *
+   * @param childDimension How big the child wants to be in the
+   *        current dimension
+   * @return a MeasureSpec for the child
+   */
+  static MeasureSpec GetChildMeasureSpec( MeasureSpec measureSpec,
+                                          LayoutLength padding,
+                                          LayoutLength childDimension );
+
+protected:
+  /**
+   * @brief Second stage initialization method for deriving classes to override
+   */
+  virtual void DoInitialize();
+
+  /**
+   * @brief Method for derived classes to implement in order to register child
+   * property types with the container.
+   *
+   * @param[in] containerType The fully qualified typename of the container
+   */
+  virtual void DoRegisterChildProperties( const std::string& containerType );
+
+  /**
+   * Callback when a child property is set on any given child
+   * @param[in] handle The handle to the child
+   * @param[in] index The index of the property that has been set
+   * @param[in] value The new value of the property
+   */
+  void OnSetChildProperties( Handle& handle, Property::Index index, Property::Value value );
+
+  /**
+   * Create default child property values suitable for this layout group or derived layouter
+   */
+  virtual void GenerateDefaultChildPropertyValues( Handle child );
+
+  /**
+   * Ask all of the children of this view to measure themselves, taking into
+   * account both the MeasureSpec requirements for this view and its padding.
+   * The heavy lifting is done in GetChildMeasureSpec.
+   *
+   * @param widthMeasureSpec The width requirements for this view
+   * @param heightMeasureSpec The height requirements for this view
+   */
+  virtual void MeasureChildren( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec );
+
+  /**
+   * Ask one of the children of this view to measure itself, taking into
+   * account both the MeasureSpec requirements for this view and its padding.
+   * The heavy lifting is done in GetChildMeasureSpec.
+   *
+   * @param child The child to measure
+   * @param parentWidthMeasureSpec The width requirements for this view
+   * @param parentHeightMeasureSpec The height requirements for this view
+   */
+  void MeasureChild( LayoutBasePtr child, MeasureSpec parentWidthMeasureSpec, MeasureSpec parentHeightMeasureSpec );
+
+  /**
+   * Ask one of the children of this view to measure itself, taking into
+   * account both the MeasureSpec requirements for this view and its padding
+   * and margins. The child must have MarginLayoutParams The heavy lifting is
+   * done in GetChildMeasureSpec.
+   *
+   * @param child The child to measure
+   * @param parentWidthMeasureSpec The width requirements for this view
+   * @param widthUsed Extra space that has been used up by the parent
+   *        horizontally (possibly by other children of the parent)
+   * @param parentHeightMeasureSpec The height requirements for this view
+   * @param heightUsed Extra space that has been used up by the parent
+   *        vertically (possibly by other children of the parent)
+   */
+  virtual void MeasureChildWithMargins( LayoutBasePtr child,
+                                        MeasureSpec parentWidthMeasureSpec,
+                                        LayoutLength widthUsed,
+                                        MeasureSpec parentHeightMeasureSpec,
+                                        LayoutLength heightUsed );
+
+private:
+  /**
+   * Second stage initialization for LayoutGroup only.
+   * This will call DoInitialize on most derived class.
+   */
+  void OnInitialize() override final;
+
+  /**
+   * @copydoc LayoutBase::OnRegisterChildProperties()
+   */
+  void OnRegisterChildProperties( const std::string& containerType ) override final;
+
+  /**
+   * @copydoc LayoutBase::OnUnparent
+   */
+  void OnUnparent() override final;
+
+  /**
+   * Callback when child is added to owner
+   */
+  void ChildAddedToOwner( Actor child );
+
+  /**
+   * Callback when child is removed from owner
+   */
+  void ChildRemovedFromOwner( Actor child );
+
+  /**
+   * Callback when an owner property is set. Triggers a relayout if it's a child property
+   */
+  void OnOwnerPropertySet( Handle& handle, Property::Index index, Property::Value value );
+
+public:
+  class Impl; // Class declaration is public so we can add devel API's in the future
+
+private:
+  std::unique_ptr<Impl> mImpl; // The implementation data for this class.
+  SlotDelegate<LayoutGroup> mSlotDelegate; ///< Slot delegate allows this class to connect safely to signals
+};
+
+} //namespace Internal
+
+inline Internal::LayoutGroup& GetImplementation( Dali::Toolkit::LayoutGroup& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "LayoutGroup handle is empty" );
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast< Internal::LayoutGroup& >( object );
+}
+
+inline const Internal::LayoutGroup& GetImplementation( const Dali::Toolkit::LayoutGroup& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "LayoutGroup handle is empty" );
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast< const Internal::LayoutGroup& >( object );
+}
+
+}//namespace Toolkit
+}//namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_GROUP_H
diff --git a/dali-toolkit/devel-api/layouting/layout-group.cpp b/dali-toolkit/devel-api/layouting/layout-group.cpp
new file mode 100644 (file)
index 0000000..d069bc0
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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-toolkit/devel-api/layouting/layout-group.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+LayoutGroup::LayoutGroup()
+: LayoutBase()
+{
+}
+
+LayoutGroup::LayoutId LayoutGroup::Add( LayoutBase& child )
+{
+  return GetImplementation( *this ).Add( GetImplementation(child) );
+}
+
+void LayoutGroup::Remove( LayoutGroup::LayoutId childId )
+{
+  GetImplementation( *this ).Remove( childId );
+}
+
+void LayoutGroup::Remove( LayoutBase& child )
+{
+  GetImplementation( *this ).Remove( GetImplementation(child) );
+}
+
+LayoutBase LayoutGroup::GetChild( LayoutGroup::LayoutId childId ) const
+{
+  Internal::LayoutBasePtr child = GetImplementation( *this ).GetChild( childId );
+  return LayoutBase( child.Get() );
+}
+
+LayoutBase LayoutGroup::GetChildAt( unsigned int childId ) const
+{
+  Internal::LayoutBasePtr child = GetImplementation( *this ).GetChildAt( childId );
+  return LayoutBase( child.Get() );
+}
+
+unsigned int LayoutGroup::GetChildCount() const
+{
+  return GetImplementation( *this ).GetChildCount();
+}
+
+LayoutGroup::LayoutGroup( Internal::LayoutGroup* layoutGroup )
+: LayoutBase( layoutGroup )
+{
+}
+
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/layout-group.h b/dali-toolkit/devel-api/layouting/layout-group.h
new file mode 100644 (file)
index 0000000..61d81e2
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_LAYOUT_GROUP_H
+#define DALI_TOOLKIT_LAYOUTING_LAYOUT_GROUP_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 <memory>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+#include <dali-toolkit/devel-api/layouting/layout-base.h>
+#include <dali-toolkit/devel-api/layouting/measure-spec.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Internal
+{
+class LayoutGroup;
+}
+
+
+/**
+ * A layout that has layout children. Implements LayoutBase.
+ * It can both layout it's children, and be laid out by a parent container.
+ *
+ * A layout group automatically handles adding a Control container's children to itself,
+ * both on startup and on child add/remove. If this functionality is not desired, this needs
+ * splitting into two classes; one that manages just the layout part, and the other which
+ * handles Actor hierarchy. (@todo Consider doing this anyway...)
+ *
+ * This handle class allows the application to set up layout properties for the layout group;
+ * it doesn't access measure/layout directly.
+ *
+ * To write a new layout, inherit from both LayoutGroup handle and Internal::LayoutGroup body.
+ *
+ */
+class DALI_IMPORT_API LayoutGroup : public LayoutBase
+{
+public:
+  using LayoutId = unsigned int;
+  static const unsigned int UNKNOWN_ID = 0;
+
+  enum PropertyRange
+  {
+    CHILD_PROPERTY_START_INDEX = CHILD_PROPERTY_REGISTRATION_START_INDEX+100,
+    CHILD_PROPERTY_END_INDEX   = CHILD_PROPERTY_START_INDEX+1000
+  };
+
+  struct ChildProperty
+  {
+    enum
+    {
+      MARGIN_SPECIFICATION = CHILD_PROPERTY_START_INDEX,
+    };
+  };
+
+
+  /**
+   * @brief Creates an uninitialized LayoutGroup handle.
+   *
+   * LayoutGroup is intended as a base class, and as such, does not have a New method.
+   *
+   * Calling member functions with an uninitialized handle is not allowed.
+   */
+  LayoutGroup();
+
+  /**
+   * @brief Default Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~LayoutGroup() = default;
+
+  /**
+   * @brief Copy constructor
+   */
+  LayoutGroup(const LayoutGroup& copy) = default;
+
+  /**
+   * @brief Assigment operator
+   */
+  LayoutGroup& operator=(const LayoutGroup& rhs) = default;
+
+  /**
+   * @brief Downcasts a handle to a LayoutGroup handle.
+   *
+   * If handle points to a LayoutGroup, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+
+   * @param[in] handle to an object
+   * @return Handle to a LayoutGroup or an uninitialized handle
+   */
+  static LayoutGroup DownCast( BaseHandle handle );
+
+  /**
+   * @brief Add a child layout to the layout group
+   *
+   * @param[in] childLayout The layout to add.
+   * @return an Id of the child.
+   */
+  LayoutId Add( LayoutBase& childLayout );
+
+  /**
+   * @brief Add a child layout to the layout group
+   *
+   * @param[in] childId the id of the child to remove
+   */
+  void Remove( LayoutId childId );
+
+  /**
+   * @brief Remove a child layout from the layout group
+   *
+   * @param[in] childLayout The layout to remove.
+   */
+  void Remove( LayoutBase& childLayout );
+
+  /**
+   * @brief Get the child at the given index.
+   *
+   * @param[in] index The index of the child.
+   */
+  LayoutBase GetChildAt( unsigned int index ) const;
+
+  /**
+   * @brief Get the count of the children of the layout
+   *
+   * @return the count of the children of the layout
+   */
+  unsigned int GetChildCount() const ;
+
+  /**
+   * @brief Get the child referenced by childId.
+   *
+   * @param[in] childId The id of the child to get
+   * @return A handle to the child layout, or empty if not found
+   */
+  LayoutBase GetChild( LayoutId childId ) const ;
+
+  /**
+   * Delete template method to remove implicit casting to integer types.
+   */
+  template <typename T>
+    LayoutBase GetChild( T childId ) = delete;
+
+
+public:
+  /// @cond internal
+  /**
+   * @brief This constructor is used by LayoutGroup::New() methods.
+   *
+   * @param[in] actor A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL LayoutGroup( Internal::LayoutGroup* layoutGroup );
+  /// @endcond
+};
+
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_LAYOUT_GROUP_H
diff --git a/dali-toolkit/devel-api/layouting/layout-length.h b/dali-toolkit/devel-api/layouting/layout-length.h
new file mode 100644 (file)
index 0000000..94f7ae0
--- /dev/null
@@ -0,0 +1,191 @@
+#ifndef DALI_TOOLKIT_DEVEL_LAYOUT_LENGTH_H
+#define DALI_TOOLKIT_DEVEL_LAYOUT_LENGTH_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 <cstdint>
+#include <iostream>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+/**
+ * @brief A type that represents a layout length.
+ *
+ * Currently, this implies pixels, but could be extended to handle device dependant sizes, etc.
+ */
+class LayoutLength
+{
+public:
+  using IntType = int;
+
+  LayoutLength( IntType value )
+  : mValue( value )
+  {
+  }
+
+  LayoutLength( const LayoutLength& layoutLength )
+  : mValue( layoutLength.mValue )
+  {
+  }
+
+  LayoutLength& operator=(const LayoutLength& rhs)
+  {
+    mValue = rhs.mValue;
+    return *this;
+  }
+
+  bool operator==( const LayoutLength& rhs )
+  {
+    return mValue == rhs.mValue;
+  }
+
+  bool operator==( LayoutLength::IntType rhs )
+  {
+    return mValue == rhs;
+  }
+
+  bool operator!=( const LayoutLength& rhs )
+  {
+    return !operator==(rhs);
+  }
+
+  bool operator<( const LayoutLength& rhs )
+  {
+    return mValue < rhs.mValue;
+  }
+
+  bool operator<( const LayoutLength rhs ) const
+  {
+    return mValue < rhs.mValue;
+  }
+
+  bool operator<=( const LayoutLength& rhs )
+  {
+    return mValue <= rhs.mValue;
+  }
+  bool operator<=( LayoutLength rhs )
+  {
+    return mValue <= rhs.mValue;
+  }
+  bool operator>( const LayoutLength& rhs )
+  {
+    return mValue > rhs.mValue;
+  }
+  bool operator>( LayoutLength rhs )
+  {
+    return mValue > rhs.mValue;
+  }
+  bool operator>=( const LayoutLength& rhs )
+  {
+    return mValue >= rhs.mValue;
+  }
+  bool operator>=( LayoutLength rhs )
+  {
+    return mValue >= rhs.mValue;
+  }
+
+  LayoutLength operator+( const LayoutLength& rhs )
+  {
+    return mValue + rhs.mValue;
+  }
+
+  LayoutLength operator+( LayoutLength::IntType rhs )
+  {
+    return mValue + rhs;
+  }
+
+  LayoutLength operator-( const LayoutLength& rhs )
+  {
+    return mValue - rhs.mValue;
+  }
+  LayoutLength operator-( LayoutLength::IntType rhs )
+  {
+    return mValue - rhs;
+  }
+
+  LayoutLength& operator+=( const LayoutLength& rhs )
+  {
+    mValue += rhs.mValue;
+    return *this;
+  }
+  LayoutLength& operator+=( LayoutLength::IntType rhs )
+  {
+    mValue += rhs;
+    return *this;
+  }
+
+  LayoutLength& operator-=( const LayoutLength& rhs )
+  {
+    mValue -= rhs.mValue;
+    return *this;
+  }
+
+  LayoutLength& operator-=( LayoutLength::IntType rhs )
+  {
+    mValue -= rhs;
+    return *this;
+  }
+
+  LayoutLength operator/( const LayoutLength& rhs )
+  {
+    return mValue / rhs.mValue;
+  }
+  LayoutLength operator/(  LayoutLength::IntType rhs )
+  {
+    return mValue / rhs;
+  }
+
+  LayoutLength operator*( const LayoutLength& rhs )
+  {
+    return mValue * rhs.mValue;
+  }
+  LayoutLength operator*( LayoutLength::IntType rhs )
+  {
+    return mValue * rhs;
+  }
+  LayoutLength operator*( float rhs )
+  {
+    return LayoutLength(LayoutLength::IntType(float(mValue) * rhs));
+  }
+
+  operator float()
+  {
+    return float( mValue );
+  }
+
+  IntType mValue;
+};
+
+/**
+ * @brief Prints a LayoutLength
+ *
+ * @param[in] o The output stream operator
+ * @param[in] layoutLength the layout length to print
+ * @return The output stream operator
+ */
+inline std::ostream& operator<<( std::ostream& o, const LayoutLength& layoutLength )
+{
+  return o<<layoutLength.mValue;
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_DEVEL_LAYOUT_LENGTH_H
diff --git a/dali-toolkit/devel-api/layouting/layout-parent-impl.h b/dali-toolkit/devel-api/layouting/layout-parent-impl.h
new file mode 100644 (file)
index 0000000..392a2ab
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_PARENT_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_PARENT_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.
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Interface that allows a layout to determine its layout parent.
+ *
+ * Needed to prevent circular inheritance - most LayoutBases have a parent,
+ * but parenting is provided by LayoutGroup, which is a sub-class of LayoutBase.
+ */
+class DALI_IMPORT_API LayoutParent
+{
+public:
+  /**
+   * Get the parent of this layout.
+   */
+  virtual LayoutParent* GetParent() = 0;
+
+protected:
+  virtual ~LayoutParent()
+  {
+  }
+};
+
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_PARENT_H
diff --git a/dali-toolkit/devel-api/layouting/layout-size.h b/dali-toolkit/devel-api/layouting/layout-size.h
new file mode 100644 (file)
index 0000000..c5ab2dd
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef DALI_TOOLKIT_DEVEL_LAYOUT_SIZE_H
+#define DALI_TOOLKIT_DEVEL_LAYOUT_SIZE_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-toolkit/devel-api/layouting/layout-length.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+/**
+ * This class represents a layout size (width and height)
+ */
+class LayoutSize
+{
+public:
+  LayoutSize()
+  : x(0u),
+    y(0u)
+  {
+  }
+
+  LayoutSize( LayoutLength::IntType anX, LayoutLength::IntType aY )
+  : x( anX ),
+    y( aY )
+  {
+  }
+
+  LayoutSize( const LayoutSize& layoutSize )
+  : x( layoutSize.x ),
+    y( layoutSize.y )
+  {
+  }
+
+  LayoutSize& operator=(const LayoutSize& rhs)
+  {
+    x = rhs.x;
+    y = rhs.y;
+    return *this;
+  }
+
+  LayoutLength::IntType GetWidth()
+  {
+    return width;
+  }
+
+  LayoutLength::IntType GetHeight()
+  {
+    return height;
+  }
+
+  void SetWidth(LayoutLength::IntType value)
+  {
+    width=value;
+  }
+  void SetHeight(LayoutLength::IntType value)
+  {
+    height=value;
+  }
+  void SetWidth(LayoutLength value)
+  {
+    width=value.mValue;
+  }
+  void SetHeight(LayoutLength value)
+  {
+    height=value.mValue;
+  }
+
+  bool operator==( const LayoutSize& rhs )
+  {
+    return x==rhs.x && y==rhs.y;
+  }
+
+  union
+  {
+    LayoutLength::IntType x;
+    LayoutLength::IntType width;
+  };
+
+  union
+  {
+    LayoutLength::IntType y;
+    LayoutLength::IntType height;
+  };
+};
+
+/**
+ * @brief Prints a LayoutSize
+ *
+ * @param[in] o The output stream operator
+ * @param[in] layoutSize the layout size to print
+ * @return The output stream operator
+ */
+inline std::ostream& operator<< (std::ostream& o, const LayoutSize& layoutSize)
+{
+  return o << "[" << layoutSize.x << ", " << layoutSize.y << "]";
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_DEVEL_LAYOUT_SIZE_H
diff --git a/dali-toolkit/devel-api/layouting/measure-spec.h b/dali-toolkit/devel-api/layouting/measure-spec.h
new file mode 100644 (file)
index 0000000..f766247
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_MEASURE_SPEC_H
+#define DALI_TOOLKIT_LAYOUTING_MEASURE_SPEC_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-toolkit/devel-api/layouting/layout-length.h>
+
+#include <sstream>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+/**
+ * A MeasureSpec is used during the Measure pass by a LayoutGroup to inform it's children
+ * how to be measured. For instance, it may measure a child with an exact width and an unspecified
+ * height in order to determine height for width.
+ */
+class DALI_IMPORT_API MeasureSpec
+{
+public:
+  using IntType = LayoutLength::IntType;
+
+  enum class Mode
+  {
+    UNSPECIFIED, ///< This is used by a parent to determine the desired dimension of a child layout.
+    EXACTLY, /** This is used by a parent to impose an exact size on the child. The child must use
+                 this size, and guarantee that all of its descendants will fit within this size */
+    AT_MOST /** This is used by the parent to impose a maximum size on the child. The child must guarantee
+             * that it and all of it's descendants will fit within this size. */
+  };
+
+  MeasureSpec( LayoutLength measureSpec, MeasureSpec::Mode mode )
+  : mSize( measureSpec.mValue ),
+    mMode( mode )
+  {
+  }
+
+  MeasureSpec( IntType measureSpec )
+  : mSize( measureSpec ),
+    mMode( Mode::UNSPECIFIED )
+  {
+  }
+
+  ~MeasureSpec() = default;
+
+  MeasureSpec& operator=( const MeasureSpec& rhs )
+  {
+    this->mSize = rhs.mSize;
+    this->mMode = rhs.mMode;
+    return *this;
+  }
+
+  bool operator==( MeasureSpec value )
+  {
+    return mSize == value.mSize;
+  }
+
+  bool operator!=( MeasureSpec value )
+  {
+    return mSize != value.mSize;
+  }
+
+  /**
+   * @brief Get the mode of the measure spec.
+   *
+   * @return The mode of the measure spec
+   */
+  MeasureSpec::Mode GetMode() const
+  {
+    return mMode;
+  }
+
+  /**
+   * @brief Get the size of the measure spec
+   *
+   * @return the size of the measure spec
+   */
+  IntType GetSize() const
+  {
+    return mSize;
+  }
+
+  /**
+   * @brief Adjust the measure size by the given delta.
+   *
+   * Used only for EXACT and AT_MOST modes.
+   * @param[in] measureSpec the measure spec to adjust
+   * @param[in] delta A positive or negative value to adjust the measure spec by.
+   *
+   * @note if the adjusted size is negative, it is zeroed.
+   * @return A new measure spec with the adjusted values.
+   */
+  static MeasureSpec Adjust( MeasureSpec measureSpec, int delta )
+  {
+    auto mode = measureSpec.GetMode();
+    auto size = measureSpec.GetSize();
+
+    if( mode == MeasureSpec::Mode::UNSPECIFIED )
+    {
+      return MeasureSpec( size, MeasureSpec::Mode::UNSPECIFIED );
+    }
+
+    if( delta < 0 && measureSpec.mSize < static_cast<IntType>(abs(delta)) )
+    {
+      size = 0;
+    }
+    else
+    {
+      size += delta;
+    }
+    return MeasureSpec( size, mode );
+  }
+
+public:
+  IntType  mSize; ///< The specified size
+  Mode     mMode; ///< The measure mode
+};
+
+inline std::ostream& operator<< (std::ostream& o, const MeasureSpec& measureSpec )
+{
+  return o << ( (measureSpec.GetMode() == MeasureSpec::Mode::UNSPECIFIED ? "Unspecified"
+                 : (measureSpec.GetMode() == MeasureSpec::Mode::EXACTLY ? "Exactly":"At most" ) ) )
+           << " " << measureSpec.GetSize();
+}
+
+} //namespace Toolkit
+} //namespace Dali
+
+
+#endif // DALI_TOOLKIT_LAYOUTING_MEASURE_SPEC_H
diff --git a/dali-toolkit/devel-api/layouting/measured-size.h b/dali-toolkit/devel-api/layouting/measured-size.h
new file mode 100644 (file)
index 0000000..ff937cf
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_MEASURED_SIZE_H
+#define DALI_TOOLKIT_LAYOUTING_MEASURED_SIZE_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-toolkit/devel-api/layouting/layout-length.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+/**
+ * Class that encodes a measurement and a measure state, which is set if the measured size is too small.
+ */
+class DALI_IMPORT_API MeasuredSize
+{
+public:
+
+  enum State
+  {
+    MEASURED_SIZE_OK, ///< The measured size is good
+    MEASURED_SIZE_TOO_SMALL ///< The measured size is too small
+  };
+
+  MeasuredSize()
+  : mMeasuredSize( 0u )
+  {
+  }
+
+  MeasuredSize( LayoutLength measuredSize )
+  : mMeasuredSize( measuredSize ),
+    mState ( MeasuredSize::State::MEASURED_SIZE_OK )
+  {
+  }
+
+  MeasuredSize( LayoutLength measuredSize, MeasuredSize::State state )
+  : mMeasuredSize( measuredSize ),
+    mState( state )
+  {
+  }
+
+  ~MeasuredSize() = default;
+
+  MeasuredSize& operator=( const MeasuredSize& rhs )
+  {
+    this->mMeasuredSize = rhs.mMeasuredSize;
+    this->mState = rhs.mState;
+    return *this;
+  }
+
+  MeasuredSize& operator=( LayoutLength::IntType rhs )
+  {
+    this->mMeasuredSize = rhs;
+    this->mState = State::MEASURED_SIZE_OK;
+    return *this;
+  }
+
+  inline bool operator==( MeasuredSize value )
+  {
+    return mMeasuredSize == value.mMeasuredSize;
+  }
+
+  inline bool operator!=( MeasuredSize value )
+  {
+    return mMeasuredSize != value.mMeasuredSize;
+  }
+
+  inline operator LayoutLength::IntType()
+  {
+    return mMeasuredSize.mValue;
+  }
+
+  inline void SetState( MeasuredSize::State state )
+  {
+    mState = state;
+  }
+
+  inline MeasuredSize::State GetState()
+  {
+    return mState;
+  }
+
+  inline void SetSize( LayoutLength size )
+  {
+    mMeasuredSize = size;
+  }
+  inline LayoutLength GetSize()
+  {
+    return mMeasuredSize;
+  }
+
+private:
+  LayoutLength mMeasuredSize; ///< The measured size
+  State mState; ///< The measured state
+};
+
+} //namespace Toolkit
+} //namespace Dali
+
+
+#endif // DALI_TOOLKIT_LAYOUTING_MEASURED_SIZE_H
diff --git a/dali-toolkit/devel-api/layouting/vbox-layout.cpp b/dali-toolkit/devel-api/layouting/vbox-layout.cpp
new file mode 100644 (file)
index 0000000..b82166b
--- /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/vbox-layout.h>
+
+//EXTERNAL HEADERS
+//INTERNAL HEADERS
+#include <dali-toolkit/internal/layouting/vbox-layout-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+VboxLayout::VboxLayout()
+{
+}
+
+VboxLayout VboxLayout::New()
+{
+  Internal::VboxLayoutPtr internal = Internal::VboxLayout::New();
+  return VboxLayout( internal.Get() );
+}
+
+VboxLayout VboxLayout::DownCast( BaseHandle handle )
+{
+  return VboxLayout( dynamic_cast< Dali::Toolkit::Internal::VboxLayout*>( handle.GetObjectPtr() ) );
+}
+
+VboxLayout::VboxLayout( const VboxLayout& other )
+: LayoutGroup( other )
+{
+}
+
+VboxLayout& VboxLayout::operator=( const VboxLayout& other )
+{
+  if( &other != this )
+  {
+    LayoutGroup::operator=( other );
+  }
+  return *this;
+}
+
+void VboxLayout::SetCellPadding( LayoutSize size )
+{
+  GetImplementation(*this).SetCellPadding( size );
+}
+
+LayoutSize VboxLayout::GetCellPadding()
+{
+  return GetImplementation(*this).GetCellPadding();
+}
+
+VboxLayout::VboxLayout( Dali::Toolkit::Internal::VboxLayout* object )
+: LayoutGroup( object )
+{
+}
+
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/vbox-layout.h b/dali-toolkit/devel-api/layouting/vbox-layout.h
new file mode 100644 (file)
index 0000000..78e5bc2
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_VBOX_LAYOUT_H
+#define DALI_TOOLKIT_LAYOUTING_VBOX_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>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class VboxLayout;
+}
+
+/**
+ * This class implements a vertical box layout, automatically handling
+ * right to left or left to right direction change.
+ */
+class DALI_IMPORT_API VboxLayout : public LayoutGroup
+{
+public:
+
+  enum PropertyRange
+  {
+    CHILD_PROPERTY_START_INDEX = LayoutGroup::CHILD_PROPERTY_START_INDEX+100,
+    CHILD_PROPERTY_END_INDEX   = CHILD_PROPERTY_START_INDEX+1000
+  };
+
+  struct ChildProperty
+  {
+    enum
+    {
+      WEIGHT = CHILD_PROPERTY_START_INDEX,
+    };
+  };
+
+  /**
+   * @brief Creates an uninitialized VboxLayout handle.
+   *
+   * Initialize it using VboxLayout::New().
+   * Calling member functions with an uninitialized handle is not allowed.
+   */
+  VboxLayout();
+
+  /**
+   * @brief Creates a VboxLayout object.
+   */
+  static VboxLayout New();
+
+  /**
+   * @brief Downcasts a handle to a VboxLayout handle.
+   *
+   * If handle points to a VboxLayout, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+
+   * @param[in] handle to an object
+   * @return Handle to a VboxLayout or an uninitialized handle
+   */
+  static VboxLayout DownCast( BaseHandle handle );
+
+  /**
+   * @brief Copy constructor
+   */
+  VboxLayout( const VboxLayout& other );
+
+  /**
+   * @brief Assigment operator
+   */
+  VboxLayout& operator=( const VboxLayout& other );
+
+  /**
+   * @brief Default destructor.
+   *
+   * This is non-virtual, since derived Handle types must not contain data or virtual methods
+   */
+  ~VboxLayout()=default;
+
+  /**
+   * @brief Set the padding between cells in the layout
+   *
+   * @param[in] size The padding between cells.
+   */
+  void SetCellPadding( LayoutSize size );
+
+  /**
+   * @brief Get the padding between cells in the layout
+   *
+   * @return The padding between cells.
+   */
+  LayoutSize GetCellPadding();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by VboxLayout::New() methods.
+   *
+   * @param[in] actor A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL VboxLayout( Internal::VboxLayout* body );
+  /// @endcond
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_VBOX_LAYOUT_H
index af3aac4..dba3d10 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * 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.
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
-#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
-#include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/public-api/visuals/visual-properties.h>
-#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
 
 namespace Dali
 {
@@ -317,6 +317,7 @@ Control::Impl::Impl( Control& controlImpl )
 : mControlImpl( controlImpl ),
   mState( Toolkit::DevelControl::NORMAL ),
   mSubStateName(""),
+  mLayout( NULL ),
   mLeftFocusableActorId( -1 ),
   mRightFocusableActorId( -1 ),
   mUpFocusableActorId( -1 ),
@@ -577,7 +578,7 @@ Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
 
 void Control::Impl::EnableVisual( Property::Index index, bool enable )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual (%d)\n", index);
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable?"T":"F");
 
   RegisteredVisualContainer::Iterator iter;
   if ( FindVisual( index, mVisuals, iter ) )
@@ -604,6 +605,10 @@ void Control::Impl::EnableVisual( Property::Index index, bool enable )
       }
     }
   }
+  else
+  {
+    DALI_LOG_WARNING( "Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable?"T":"F" );
+  }
 }
 
 bool Control::Impl::IsVisualEnabled( Property::Index index ) const
@@ -635,7 +640,7 @@ void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
 // Called by a Visual when it's resource is ready
 void Control::Impl::ResourceReady( Visual::Base& object)
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceReady replacements pending[%d]\n", mRemoveVisuals.Count() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count() );
 
   Actor self = mControlImpl.Self();
 
@@ -706,82 +711,92 @@ Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus( Property
   return Toolkit::Visual::ResourceStatus::PREPARING;
 }
 
-Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData& handle )
+
+
+void Control::Impl::AddTransitions( Dali::Animation& animation,
+                                    const Toolkit::TransitionData& handle,
+                                    bool createAnimation )
 {
-  Dali::Animation transition;
+  // Setup a Transition from TransitionData.
   const Internal::TransitionData& transitionData = Toolkit::GetImplementation( handle );
-
-  if( transitionData.Count() > 0 )
+  TransitionData::Iterator end = transitionData.End();
+  for( TransitionData::Iterator iter = transitionData.Begin() ;
+       iter != end; ++iter )
   {
-    // Setup a Transition from TransitionData.
-    TransitionData::Iterator end = transitionData.End();
-    for( TransitionData::Iterator iter = transitionData.Begin() ;
-         iter != end; ++iter )
-    {
-      TransitionData::Animator* animator = (*iter);
+    TransitionData::Animator* animator = (*iter);
 
-      Toolkit::Visual::Base visual = GetVisualByName( mVisuals, animator->objectName );
+    Toolkit::Visual::Base visual = GetVisualByName( mVisuals, animator->objectName );
 
-      if( visual )
-      {
+    if( visual )
+    {
 #if defined(DEBUG_ENABLED)
-        Dali::TypeInfo typeInfo;
-        ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
-        if( controlWrapperImpl )
-        {
-          typeInfo = controlWrapperImpl->GetTypeInfo();
-        }
+      Dali::TypeInfo typeInfo;
+      ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
+      if( controlWrapperImpl )
+      {
+        typeInfo = controlWrapperImpl->GetTypeInfo();
+      }
 
-        DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n",
-                       visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" );
+      DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n",
+                     visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" );
 #endif
-        Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
-        visualImpl.AnimateProperty( transition, *animator );
-      }
-      else
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.AnimateProperty( animation, *animator );
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
+      // Otherwise, try any actor children of control (Including the control)
+      Actor child = mControlImpl.Self().FindChildByName( animator->objectName );
+      if( child )
       {
-        DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
-        // Otherwise, try any actor children of control (Including the control)
-        Actor child = mControlImpl.Self().FindChildByName( animator->objectName );
-        if( child )
+        Property::Index propertyIndex = DevelHandle::GetPropertyIndex( child, animator->propertyKey );
+        if( propertyIndex != Property::INVALID_INDEX )
         {
-          Property::Index propertyIndex = DevelHandle::GetPropertyIndex( child, animator->propertyKey );
-          if( propertyIndex != Property::INVALID_INDEX )
+          if( animator->animate == false )
           {
-            if( animator->animate == false )
+            if( animator->targetValue.GetType() != Property::NONE )
             {
-              if( animator->targetValue.GetType() != Property::NONE )
-              {
-                child.SetProperty( propertyIndex, animator->targetValue );
-              }
+              child.SetProperty( propertyIndex, animator->targetValue );
             }
-            else // animate the property
+          }
+          else // animate the property
+          {
+            if( animator->initialValue.GetType() != Property::NONE )
+            {
+              child.SetProperty( propertyIndex, animator->initialValue );
+            }
+
+            if( createAnimation && !animation )
             {
-              if( animator->initialValue.GetType() != Property::NONE )
-              {
-                child.SetProperty( propertyIndex, animator->initialValue );
-              }
-
-              if( ! transition )
-              {
-                transition = Dali::Animation::New( 0.1f );
-              }
-
-              transition.AnimateTo( Property( child, propertyIndex ),
-                                    animator->targetValue,
-                                    animator->alphaFunction,
-                                    TimePeriod( animator->timePeriodDelay,
-                                                animator->timePeriodDuration ) );
+              animation = Dali::Animation::New( 0.1f );
             }
+
+            animation.AnimateTo( Property( child, propertyIndex ),
+                                 animator->targetValue,
+                                 animator->alphaFunction,
+                                 TimePeriod( animator->timePeriodDelay,
+                                             animator->timePeriodDuration ) );
           }
         }
       }
     }
   }
+}
+
+Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData& transitionData )
+{
+  Dali::Animation transition;
 
+  if( transitionData.Count() > 0 )
+  {
+    AddTransitions( transition, transitionData, true );
+  }
   return transition;
 }
 
+
+
 void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes )
 {
   RegisteredVisualContainer::Iterator iter;
@@ -1407,6 +1422,24 @@ bool Control::Impl::FilterKeyEvent( const KeyEvent& event )
   return consumed;
 }
 
+Toolkit::Internal::LayoutBasePtr Control::Impl::GetLayout() const
+{
+  return mLayout;
+}
+
+void Control::Impl::SetLayout( Toolkit::Internal::LayoutBase& layout )
+{
+  if( mLayout )
+  {
+    mLayout->Unparent();
+    mLayout.Reset();
+  }
+  mLayout = &layout;
+
+  auto controlHandle = Toolkit::Control::DownCast( mControlImpl.Self() ); // Get a handle of this control implementation without copying internals.
+  mLayout->Initialize( controlHandle, controlHandle.GetTypeName() ); // LayoutGroup takes ownership of existing children
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
index a0ff3d1..31815f6 100755 (executable)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_CONTROL_DATA_IMPL_H
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * 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.
@@ -27,6 +27,7 @@
 #include <dali-toolkit/internal/visuals/visual-resource-observer.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
 #include <dali/devel-api/common/owner-container.h>
+#include <dali-toolkit/devel-api/layouting/layout-base-impl.h>
 #include <dali-toolkit/devel-api/visual-factory/visual-base.h>
 #include <dali-toolkit/internal/controls/tooltip/tooltip.h>
 #include <dali-toolkit/internal/builder/style.h>
@@ -83,7 +84,7 @@ public:
 
   /**
    * @brief Constructor.
-   * @param[in] controlImpl The control which own this implementation
+   * @param[in] controlImpl The control which owns this implementation
    */
   Impl( Control& controlImpl );
 
@@ -185,6 +186,16 @@ public:
   Toolkit::Visual::ResourceStatus GetVisualResourceStatus( Property::Index index ) const;
 
   /**
+   * @param[in,out] animation Handle to existing animation, or an empty handle that
+   * can be set to a New animation if createAnimation is true
+   * @param[in] transitionData The transition data describing the animation
+   * @param[in] createAnimation True if the animation should be created
+   */
+  void AddTransitions( Dali::Animation& animation,
+                       const Toolkit::TransitionData& transitionData,
+                       bool createAnimation = false );
+
+  /**
    * @copydoc Dali::Toolkit::DevelControl::CreateTransition()
    */
   Dali::Animation CreateTransition( const Toolkit::TransitionData& transitionData );
@@ -313,6 +324,19 @@ public:
    */
   bool FilterKeyEvent( const KeyEvent& event );
 
+  /**
+   * @brief Get the layout associated with this control, if any.
+   *
+   * @return A pointer to the layout, or NULL.
+   */
+  Toolkit::Internal::LayoutBasePtr GetLayout() const;
+
+  /**
+   * @brief Set the layout on this control.
+   * @param[in] layout Pointer to the layout
+   */
+  void SetLayout( Toolkit::Internal::LayoutBase& layout );
+
 private:
 
   /**
@@ -358,6 +382,9 @@ public:
   DevelControl::State mState;
   std::string mSubStateName;
 
+  // Layout
+  Toolkit::Internal::LayoutBasePtr mLayout;
+
   int mLeftFocusableActorId;       ///< Actor ID of Left focusable control.
   int mRightFocusableActorId;      ///< Actor ID of Right focusable control.
   int mUpFocusableActorId;         ///< Actor ID of Up focusable control.
@@ -391,6 +418,7 @@ public:
 
   RegisteredVisualContainer mRemoveVisuals;         ///< List of visuals that are being replaced by another visual once ready
 
+
   // Properties - these need to be members of Internal::Control::Impl as they access private methods/data of Internal::Control and Internal::Control::Impl.
   static const PropertyRegistration PROPERTY_1;
   static const PropertyRegistration PROPERTY_2;
index f32296b..8064510 100755 (executable)
@@ -11,6 +11,12 @@ toolkit_src_files = \
    $(toolkit_src_dir)/builder/style.cpp \
    $(toolkit_src_dir)/builder/tree-node-manipulator.cpp \
    $(toolkit_src_dir)/builder/replacement.cpp \
+   $(toolkit_src_dir)/layouting/hbox-layout-impl.cpp \
+   $(toolkit_src_dir)/layouting/vbox-layout-impl.cpp \
+   $(toolkit_src_dir)/layouting/layout-base-data-impl.cpp \
+   $(toolkit_src_dir)/layouting/layout-group-data-impl.cpp \
+   $(toolkit_src_dir)/layouting/layout-controller-debug.cpp \
+   $(toolkit_src_dir)/layouting/layout-controller-impl.cpp \
    $(toolkit_src_dir)/visuals/animated-image/animated-image-visual.cpp \
    $(toolkit_src_dir)/visuals/animated-image/image-cache.cpp \
    $(toolkit_src_dir)/visuals/animated-image/fixed-image-cache.cpp \
diff --git a/dali-toolkit/internal/layouting/hbox-layout-impl.cpp b/dali-toolkit/internal/layouting/hbox-layout-impl.cpp
new file mode 100644 (file)
index 0000000..181a036
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * 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/hbox-layout-impl.h>
+
+//EXTERNAL HEADERS
+//INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/extents.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali-toolkit/devel-api/layouting/layout-base.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+HboxLayoutPtr HboxLayout::New()
+{
+  HboxLayoutPtr layout( new HboxLayout() );
+  return layout;
+}
+
+HboxLayout::HboxLayout()
+: LayoutGroup(),
+  mCellPadding( 0, 0 ),
+  mTotalLength( 0 )
+{
+}
+
+HboxLayout::~HboxLayout()
+{
+}
+
+void HboxLayout::DoInitialize()
+{
+}
+
+void HboxLayout::DoRegisterChildProperties( const std::string& containerType )
+{
+  auto typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( containerType );
+  if( typeInfo )
+  {
+    Property::IndexContainer indices;
+    typeInfo.GetChildPropertyIndices( indices );
+
+    if( std::find( indices.Begin(), indices.End(), Toolkit::HboxLayout::ChildProperty::WEIGHT ) == indices.End() )
+    {
+      ChildPropertyRegistration( typeInfo.GetName(), "weight",
+                                 Toolkit::HboxLayout::ChildProperty::WEIGHT, Property::FLOAT );
+    }
+  }
+}
+
+void HboxLayout::OnChildAdd( LayoutBase& child )
+{
+  auto owner = child.GetOwner();
+  owner.SetProperty( Toolkit::HboxLayout::ChildProperty::WEIGHT, 1.0f );
+}
+
+void HboxLayout::SetCellPadding( LayoutSize size )
+{
+  mCellPadding = size;
+}
+
+LayoutSize HboxLayout::GetCellPadding()
+{
+  return mCellPadding;
+}
+
+void HboxLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+#if defined(DEBUG_ENABLED)
+  auto actor = Actor::DownCast(GetOwner());
+
+  std::ostringstream oss;
+  oss << "HBoxLayout::OnMeasure  ";
+  if( actor )
+  {
+    oss << "Actor Id:" << actor.GetId() << " Name:" << actor.GetName() << "  ";
+  }
+  oss << "widthMeasureSpec:" << widthMeasureSpec << " heightMeasureSpec:" << heightMeasureSpec << std::endl;
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, oss.str().c_str() );
+#endif
+
+  auto widthMode = widthMeasureSpec.GetMode();
+  auto heightMode = heightMeasureSpec.GetMode();
+  bool isExactly = (widthMode == MeasureSpec::Mode::EXACTLY);
+  bool matchHeight = false;
+  bool allFillParent = true;
+  LayoutLength maxHeight = 0;
+  LayoutLength alternativeMaxHeight = 0;
+  struct
+  {
+    MeasuredSize::State widthState;
+    MeasuredSize::State heightState;
+  } childState = { MeasuredSize::State::MEASURED_SIZE_OK, MeasuredSize::State::MEASURED_SIZE_OK };
+
+  // measure children, and determine if further resolution is required
+  for( unsigned int i=0; i<GetChildCount(); ++i )
+  {
+    auto childLayout = GetChildAt( i );
+    if( childLayout )
+    {
+      auto childOwner = childLayout->GetOwner();
+      auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
+
+      MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, heightMeasureSpec, 0 );
+      auto childWidth = childLayout->GetMeasuredWidth();
+      auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
+      auto length = childWidth + LayoutLength::IntType(childMargin.start + childMargin.end);
+
+      auto cellPadding = i<GetChildCount()-1 ? mCellPadding.width: 0;
+
+      if( isExactly )
+      {
+        mTotalLength += length;
+      }
+      else
+      {
+        auto totalLength = mTotalLength;
+        mTotalLength = std::max( totalLength, totalLength + length + cellPadding );
+      }
+
+      bool matchHeightLocally = false;
+      if( heightMode != MeasureSpec::Mode::EXACTLY && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
+      {
+        // Will have to re-measure at least this child when we know exact height.
+        matchHeight = true;
+        matchHeightLocally = true;
+      }
+
+      auto marginHeight = LayoutLength( childMargin.top + childMargin.bottom );
+      auto childHeight = childLayout->GetMeasuredHeight() + marginHeight;
+
+      if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
+      {
+        childState.widthState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
+      }
+      if( childLayout->GetMeasuredHeightAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
+      {
+        childState.heightState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
+      }
+
+      maxHeight = std::max( maxHeight, childHeight );
+      allFillParent = ( allFillParent && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT );
+      alternativeMaxHeight = std::max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
+    }
+  }
+
+  Extents padding = GetPadding();
+  mTotalLength += padding.start + padding.end;
+  auto widthSize = mTotalLength;
+  widthSize = std::max( widthSize, GetSuggestedMinimumWidth() );
+  MeasuredSize widthSizeAndState = ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK);
+  widthSize = widthSizeAndState.GetSize();
+
+  if( !allFillParent && heightMode != MeasureSpec::Mode::EXACTLY )
+  {
+    maxHeight = alternativeMaxHeight;
+  }
+  maxHeight += padding.top + padding.bottom;
+  maxHeight = std::max( maxHeight, GetSuggestedMinimumHeight() );
+
+  widthSizeAndState.SetState( childState.widthState );
+
+  SetMeasuredDimensions( widthSizeAndState,
+                         ResolveSizeAndState( maxHeight, heightMeasureSpec, childState.heightState ) );
+
+  if( matchHeight )
+  {
+    ForceUniformHeight( GetChildCount(), widthMeasureSpec );
+  }
+}
+
+void HboxLayout::ForceUniformHeight( int count, MeasureSpec widthMeasureSpec )
+{
+  // Pretend that the linear layout has an exact size. This is the measured height of
+  // ourselves. The measured height should be the max height of the children, changed
+  // to accommodate the heightMeasureSpec from the parent
+  auto uniformMeasureSpec = MeasureSpec( GetMeasuredHeight(), MeasureSpec::Mode::EXACTLY );
+  for (int i = 0; i < count; ++i)
+  {
+    LayoutBasePtr childLayout = GetChildAt(i);
+    if( childLayout != nullptr )
+    {
+      auto childOwner = childLayout->GetOwner();
+      auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
+      auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
+
+      if( desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
+      {
+        // Temporarily force children to reuse their old measured width
+        int oldWidth = desiredWidth;
+        childOwner.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, childLayout->GetMeasuredWidth().mValue );
+
+        // Remeasure with new dimensions
+        MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, uniformMeasureSpec, 0);
+
+        childOwner.SetProperty( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION, oldWidth );
+      }
+    }
+  }
+}
+
+void HboxLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+  auto owner = GetOwner();
+  auto actor = Actor::DownCast(owner);
+  bool isLayoutRtl = actor ? actor.GetProperty<bool>( Actor::Property::LAYOUT_DIRECTION ) : false;
+
+  Extents padding = GetPadding();
+
+  LayoutLength childTop( 0 );
+  LayoutLength childLeft( padding.start );
+
+  // Where bottom of child should go
+  auto height = bottom - top;
+
+  // Space available for child
+  auto childSpace = height - padding.top - padding.bottom;
+
+  auto count = GetChildCount();
+
+  int start = 0;
+  int dir = 1;
+
+  // In case of RTL, start drawing from the last child.
+  // @todo re-work to draw the first child from the right edge, and move leftwards.
+  // (Should have an alignment also)
+  if( isLayoutRtl ) {
+    start = count - 1;
+    dir = -1;
+  }
+
+  for( unsigned int i = 0; i < count; i++)
+  {
+    int childIndex = start + dir * i;
+    LayoutBasePtr childLayout = GetChildAt( childIndex );
+    if( childLayout != nullptr )
+    {
+      auto childWidth = childLayout->GetMeasuredWidth();
+      auto childHeight = childLayout->GetMeasuredHeight();
+
+      auto childOwner = childLayout->GetOwner();
+      auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
+
+      childTop = LayoutLength(padding.top) + ((childSpace - childHeight) / 2) + childMargin.top - childMargin.bottom;
+
+      childLeft += childMargin.start;
+      childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
+      childLeft += childWidth + childMargin.end + mCellPadding.width;
+    }
+  }
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/hbox-layout-impl.h b/dali-toolkit/internal/layouting/hbox-layout-impl.h
new file mode 100644 (file)
index 0000000..ea009ae
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_HBOX_LAYOUT_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_HBOX_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/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali-toolkit/devel-api/layouting/hbox-layout.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class HboxLayout;
+using HboxLayoutPtr = IntrusivePtr<HboxLayout>;
+
+class HboxLayout final : public LayoutGroup
+{
+public:
+  static HboxLayoutPtr New();
+
+public:
+  void SetCellPadding( LayoutSize size );
+  LayoutSize GetCellPadding();
+
+protected:
+  HboxLayout();
+  virtual ~HboxLayout();
+
+  /**
+   * @copydoc LayoutBase::DoInitialize
+   */
+  virtual void DoInitialize() override;
+
+  /**
+   * @copydoc LayoutBase::DoRegisterChildProperties()
+   */
+  virtual void DoRegisterChildProperties( const std::string& containerType ) override;
+
+  /**
+   * @copydoc LayoutBase::OnChildAdd
+   */
+  virtual void OnChildAdd( LayoutBase& child ) override;
+
+  /**
+   * @copydoc LayoutBase::OnMeasure
+   */
+  virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) override;
+
+  /**
+   * @copydoc LayoutBase::OnLayout
+   */
+  virtual void OnLayout( bool changed, LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b ) override;
+
+private:
+  HboxLayout( const HboxLayout& other ) = delete;
+  HboxLayout& operator=( const HboxLayout& other ) = delete;
+
+  void ForceUniformHeight( int count, MeasureSpec widthMeasureSpec );
+
+private:
+  LayoutSize mCellPadding;
+  LayoutLength mTotalLength;
+};
+
+} // namespace Internal
+
+inline Internal::HboxLayout& GetImplementation( Dali::Toolkit::HboxLayout& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "HboxLayout handle is empty" );
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast<Internal::HboxLayout&>( object );
+}
+
+inline const Internal::HboxLayout& GetImplementation( const Dali::Toolkit::HboxLayout& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "HboxLayout handle is empty" );
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast<const Internal::HboxLayout&>( object );
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUTING_HBOX_LAYOUT_H
diff --git a/dali-toolkit/internal/layouting/layout-base-data-impl.cpp b/dali-toolkit/internal/layouting/layout-base-data-impl.cpp
new file mode 100644 (file)
index 0000000..9a1b984
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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-toolkit/internal/layouting/layout-base-data-impl.h>
+#include <dali-toolkit/devel-api/layouting/measured-size.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+bool LayoutBase::Impl::sUseZeroUnspecifiedMeasureSpec = false;
+
+
+LayoutBase::Impl::Impl()
+: mOwner( nullptr ),
+  mLayoutParent( nullptr ),
+  mOldWidthMeasureSpec( 0u ),
+  mOldHeightMeasureSpec( 0u ),
+  mMinimumSize(),
+  mMeasuredWidth(0u),
+  mMeasuredHeight(0u),
+  mLeft( 0 ),
+  mRight( 0 ),
+  mTop( 0 ),
+  mBottom( 0 ),
+  mViewFlags( 0 ),
+  mPrivateFlags( 0 ),
+  mAnimated(false)
+{
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/layout-base-data-impl.h b/dali-toolkit/internal/layouting/layout-base-data-impl.h
new file mode 100644 (file)
index 0000000..fbf4202
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_BASE_DATA_IMPL_H_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_BASE_DATA_IMPL_H_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-toolkit/devel-api/layouting/layout-base-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-controller.h>
+#include <dali-toolkit/devel-api/layouting/layout-size.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+class LayoutParent;
+
+
+class LayoutBase::Impl
+{
+public:
+  Impl();
+
+public:
+  BaseObject* mOwner; ///< Control or Visual that owns this layout. Raw pointer to prevent cyclic references
+  LayoutParent* mLayoutParent; ///< The containing layout parent.
+
+  MeasureSpec mOldWidthMeasureSpec;
+  MeasureSpec mOldHeightMeasureSpec;
+  LayoutSize mMinimumSize;
+
+  MeasuredSize mMeasuredWidth;
+  MeasuredSize mMeasuredHeight;
+
+  Extents mMargin; ///< Distances in pixels from the edges of this view to this view's parent.
+  Extents mPadding; ///< Distances in pixels from the edges of this view to this view's content.
+
+  LayoutLength mLeft;
+  LayoutLength mRight;
+  LayoutLength mTop;
+  LayoutLength mBottom;
+
+  /**
+   * This view is visible.
+   * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
+   * android:visibility}.
+   */
+  static const int VISIBLE = 0x00000000;
+
+  /**
+   * This view is invisible, but it still takes up space for layout purposes.
+   * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
+   * android:visibility}.
+   */
+  static const int INVISIBLE = 0x00000004;
+
+  /**
+   * This view is invisible, and it doesn't take any space for layout
+   * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code
+   * android:visibility}.
+   */
+  static const int GONE = 0x00000008;
+
+  /**
+   * Mask for use with setFlags indicating bits used for visibility.
+   * {@hide}
+   */
+  static const int VISIBILITY_MASK = 0x0000000C;
+
+  static const int PRIVATE_FLAG_MEASURED_DIMENSION_SET        = 0x00000001;
+  static const int PRIVATE_FLAG_FORCE_LAYOUT                  = 0x00000002;
+  static const int PRIVATE_FLAG_LAYOUT_REQUIRED               = 0x00000004;
+  static const int PRIVATE_FLAG_IS_LAID_OUT                   = 0x00000008;
+  static const int PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT  = 0x00000010; ///< Flag indicating that a call to measure() was skipped and should be done instead when layout() is invoked.
+  static const int PRIVATE_FLAG_HAS_BOUNDS                    = 0x00000020;
+
+  int mViewFlags;
+  int mPrivateFlags;
+
+  bool mAnimated;
+
+  inline void ClearPrivateFlag( int flag )
+  {
+    mPrivateFlags &= ~flag;
+  }
+
+  inline void SetPrivateFlag( int flag )
+  {
+    mPrivateFlags |= flag;
+  }
+
+  inline bool GetPrivateFlag( int flag )
+  {
+    return ( mPrivateFlags & flag ) != 0;
+  }
+
+  static bool sUseZeroUnspecifiedMeasureSpec;
+
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_INTERNAL_LAYOUTING_LAYOUT_BASE_DATA_IMPL_H_H
diff --git a/dali-toolkit/internal/layouting/layout-controller-debug.cpp b/dali-toolkit/internal/layouting/layout-controller-debug.cpp
new file mode 100644 (file)
index 0000000..70838b4
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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-toolkit/dali-toolkit.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/layouting/layout-controller-debug.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+#if defined( DEBUG_ENABLED )
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Verbose, false, "LOG_LAYOUT_TREE" );
+
+
+void GetLayoutMeasureStateString( std::ostringstream& oss, LayoutBasePtr layout )
+{
+  if( layout )
+  {
+    auto widthSizeAndState = layout->GetMeasuredWidthAndState();
+    auto heightSizeAndState = layout->GetMeasuredHeightAndState();
+
+    oss << "LayoutMeasureState:" <<
+      "  w:" << widthSizeAndState.GetSize() << (widthSizeAndState.GetState()==MeasuredSize::MEASURED_SIZE_TOO_SMALL?"/TooSmall":"") <<
+      "  h:" << heightSizeAndState.GetSize() << (heightSizeAndState.GetState()==MeasuredSize::MEASURED_SIZE_TOO_SMALL?"/TooSmall":"");
+  }
+}
+
+void LayoutDebugMeasureStateRecurseLayout( LayoutBasePtr layout, int depth );
+
+void LayoutDebugMeasureStateRecurseActor( Actor root, int depth )
+{
+  std::ostringstream oss;
+  for(int i=0;i<depth;++i) { oss << "  "; };
+  oss << "Actor " << root.GetId() << ":" << root.GetName() << " ";
+
+  bool descendActor = true;
+  Toolkit::Control control = Toolkit::Control::DownCast( root );
+  if( control )
+  {
+    Internal::Control& controlImpl = GetImplementation( control );
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+    LayoutBasePtr layout = controlDataImpl.GetLayout();
+
+    if( layout != nullptr )
+    {
+      GetLayoutMeasureStateString( oss, layout );
+      oss << std::endl;
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, oss.str().c_str() );
+
+      auto layoutGroup = LayoutGroupPtr( dynamic_cast< LayoutGroup* >( layout.Get() ) );
+      if( layoutGroup )
+      {
+        for( unsigned int i=0; i<layoutGroup->GetChildCount(); ++i )
+        {
+          auto layoutChild = layoutGroup->GetChildAt( i );
+          LayoutDebugMeasureStateRecurseLayout( layoutChild, depth+1 );
+        }
+      }
+      descendActor = false;
+    }
+  }
+
+  if( descendActor == true )
+  {
+    oss << std::endl;
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, oss.str().c_str() );
+
+    // Depth first descent through actor children
+    for( unsigned int i = 0, count = root.GetChildCount(); i < count; ++i )
+    {
+      Actor child = root.GetChildAt( i );
+      LayoutDebugMeasureStateRecurseActor( child, depth+1 );
+    }
+  }
+}
+
+void LayoutDebugMeasureStateRecurseLayout( LayoutBasePtr layout, int depth )
+{
+  std::ostringstream oss;
+  for(int i=0;i<depth;++i) { oss << "  "; }; // indent
+
+  Actor actor = Actor::DownCast( layout->GetOwner() );
+  if( actor )
+  {
+    oss << "Actor " << actor.GetId() << ":" << actor.GetName() << " ";
+  }
+  else
+  {
+    oss << "Owner: " << layout->GetOwner().GetObjectPtr() << " ";
+  }
+
+  GetLayoutMeasureStateString( oss, layout );
+  oss << std::endl;
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, oss.str().c_str() );
+
+  auto layoutGroup = LayoutGroupPtr( dynamic_cast< LayoutGroup* >( layout.Get() ) );
+  if( layoutGroup )
+  {
+    for( unsigned int i=0; i<layoutGroup->GetChildCount(); ++i )
+    {
+      auto layoutChild = layoutGroup->GetChildAt( i );
+      LayoutDebugMeasureStateRecurseLayout( layoutChild, depth+1 );
+    }
+  }
+  else if( actor )
+  {
+    for( unsigned int i = 0, count = actor.GetChildCount(); i < count; ++i )
+    {
+      LayoutDebugMeasureStateRecurseActor( actor.GetChildAt( i ), depth + 1 );
+    }
+  }
+}
+
+
+void LayoutDebugMeasureState( Actor root )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Layout tree after measure:\n\n" );
+  LayoutDebugMeasureStateRecurseActor( root, 0 );
+}
+
+
+void LayoutDebugAfterLayoutRecurse( Actor root, int depth )
+{
+  std::ostringstream oss;
+  for(int i=0;i<depth;++i) { oss << "  "; };
+  oss << "Actor " << root.GetId() << ":" << root.GetName() << " ";
+  Toolkit::Control control = Toolkit::Control::DownCast( root );
+  if( control )
+  {
+    Internal::Control& controlImpl = GetImplementation( control );
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+    LayoutBasePtr layout = controlDataImpl.GetLayout();
+
+    if( layout )
+    {
+      auto childOwner = layout->GetOwner();
+      auto widthMeasureSpec = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
+      auto heightMeasureSpec = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
+
+      oss << "LayoutData:" << "( " << widthMeasureSpec << ", " << heightMeasureSpec << ") ";
+
+      auto actorPos  = root.GetProperty<Vector3>( Actor::Property::POSITION );
+      auto actorSize = root.GetProperty<Vector3>( Actor::Property::SIZE );
+      oss << "  ActorPos: (" << actorPos.x << ", " << actorPos.y << ")";
+      oss << "  ActorSize: (" << actorSize.width << ", " << actorSize.height << ")";
+    }
+    else
+    {
+      // Try getting layout data from parent control
+    }
+  }
+  oss << std::endl;
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, oss.str().c_str() );
+
+  // Depth first descent through actor children
+  for( unsigned int i = 0, count = root.GetChildCount(); i < count; ++i )
+  {
+    Actor child = root.GetChildAt( i );
+    LayoutDebugAfterLayoutRecurse( child, depth+1 );
+  }
+}
+
+void LayoutDebugAfterLayout( Actor root )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Layout tree after layout:\n\n" );
+  LayoutDebugAfterLayoutRecurse( root, 0 );
+}
+
+
+#endif
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/layout-controller-debug.h b/dali-toolkit/internal/layouting/layout-controller-debug.h
new file mode 100644 (file)
index 0000000..9a2323f
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_DEBUG_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_DEBUG_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/actors/actor.h>
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/devel-api/layouting/measure-spec.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+#if defined(DEBUG_ENABLED)
+
+extern void LayoutDebugMeasureState( Actor root );
+extern void LayoutDebugAfterLayout( Actor root );
+
+
+#define LAYOUT_DEBUG_MEASURE_STATES( root ) \
+  LayoutDebugMeasureState( root )
+
+#define LAYOUT_DEBUG_AFTER_LAYOUT( root ) \
+  LayoutDebugAfterLayout( root )
+
+#else
+
+
+#define LAYOUT_DEBUG_MEASURE_STATES( root )
+#define LAYOUT_DEBUG_AFTER_LAYOUT( root )
+
+#endif
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_INTERNAL_LAYOUTING_DEBUG_H
diff --git a/dali-toolkit/internal/layouting/layout-controller-impl.cpp b/dali-toolkit/internal/layouting/layout-controller-impl.cpp
new file mode 100644 (file)
index 0000000..30beba4
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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/stage.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali-toolkit/internal/layouting/layout-controller-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/layouting/layout-controller-debug.h>
+
+using namespace Dali;
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+LayoutController::LayoutController()
+: mLayoutRequested(false)
+{
+}
+
+LayoutController::~LayoutController()
+{
+}
+
+void LayoutController::Initialize()
+{
+}
+
+void LayoutController::RequestLayout( LayoutBase& layoutBase )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutController::RequestLayout\n" );
+  mLayoutRequested = true;
+
+  // Go up the tree and mark all parents to relayout
+  LayoutParent* layoutParent = layoutBase.GetParent();
+  if( layoutParent )
+  {
+    LayoutGroup& layoutGroup = static_cast< LayoutGroup& >( *layoutParent );
+    if( ! layoutGroup.IsLayoutRequested() )
+    {
+      layoutGroup.RequestLayout();
+    }
+  }
+}
+
+void LayoutController::Process()
+{
+  // Perform the full process.
+
+  if( mLayoutRequested )
+  {
+    mLayoutRequested = false;
+
+    // If window size has changed, expect stage to have already been updated
+    Stage stage = Stage::GetCurrent();
+    auto stageWidth  = stage.GetSize().width;
+    auto stageHeight = stage.GetSize().height;
+
+    auto widthSpec = MeasureSpec( stageWidth, MeasureSpec::Mode::EXACTLY );
+    auto heightSpec = MeasureSpec( stageHeight, MeasureSpec::Mode::EXACTLY );
+
+    // Test how to perform a measure on each control.
+    MeasureHierarchy( stage.GetRootLayer(), widthSpec, heightSpec );
+
+    LAYOUT_DEBUG_MEASURE_STATES( stage.GetRootLayer() );
+    PerformLayout( stage.GetRootLayer(), 0, 0, stageWidth, stageHeight );
+
+    LAYOUT_DEBUG_AFTER_LAYOUT( stage.GetRootLayer() );
+  }
+}
+
+void LayoutController::MeasureHierarchy( Actor root, MeasureSpec widthSpec, MeasureSpec heightSpec )
+{
+  // Does this actor have a layout?
+  // Yes - measure the layout. It will call this method again for each of it's children.
+  // No - recurse through actor children.
+  //
+  // If in a leaf actor with no layout, it's natural size is bubbled back up.
+  //
+  // What happens if nothing in the tree has a layout?
+
+  Toolkit::Control control = Toolkit::Control::DownCast( root );
+  if( control )
+  {
+    Internal::Control& controlImpl = GetImplementation( control );
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+    LayoutBasePtr layout = controlDataImpl.GetLayout();
+
+    if( layout )
+    {
+      layout->Measure( widthSpec, heightSpec );
+    }
+  }
+  else
+  {
+    // Depth first descent through actor children
+    for( unsigned int i = 0, count = root.GetChildCount(); i < count; ++i )
+    {
+      Actor child = root.GetChildAt( i );
+      MeasureHierarchy( child, widthSpec, heightSpec );
+    }
+  }
+}
+
+void LayoutController::PerformLayout( Actor root, int left, int top, int right, int bottom )
+{
+  Toolkit::Control control = Toolkit::Control::DownCast( root );
+  if( control )
+  {
+    Internal::Control& controlImpl = GetImplementation( control );
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+    LayoutBasePtr layout = controlDataImpl.GetLayout();
+
+    if( layout )
+    {
+      layout->Layout( left, top, right, bottom );
+    }
+  }
+  else
+  {
+    // Depth first descent through actor children
+    for( unsigned int i = 0, count = root.GetChildCount(); i < count; ++i )
+    {
+      Actor child = root.GetChildAt( i );
+      PerformLayout( child, left, top, right, bottom );
+    }
+  }
+}
+
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/layout-controller-impl.h b/dali-toolkit/internal/layouting/layout-controller-impl.h
new file mode 100644 (file)
index 0000000..4a7bdbc
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUT_CONTROLLER_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUT_CONTROLLER_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/object/base-object.h>
+#include <dali/integration-api/core.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/layouting/layout-controller.h>
+#include <dali-toolkit/devel-api/layouting/layout-base-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * @brief Layout controller handles measurement and layout of all
+ * controls that utilize Layouts.
+ */
+class LayoutController : public Dali::BaseObject, public Integration::Processor
+{
+public:
+  /**
+   * Constructor
+   */
+  LayoutController();
+
+  /**
+   * Destructor
+   */
+  ~LayoutController();
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize();
+
+  /**
+   * This marks the given layout and all its parents as dirty.
+   */
+  void RequestLayout( LayoutBase& layout );
+
+  /**
+   * Measures next level of layouts in the actor hierarchy.
+   */
+  void MeasureHierarchy( Actor root, MeasureSpec widthSpec, MeasureSpec heightSpec );
+
+  /**
+   * Perform layout of the hierarchy
+   */
+  void PerformLayout( Actor root, int left, int top, int right, int bottom );
+
+protected: // Implementation of Processor
+
+  /**
+   * @copydoc Dali::Integration::Processor::Process()
+   */
+  virtual void Process();
+
+private:
+  bool mLayoutRequested;
+};
+
+} // namespace Internal
+
+inline Internal::LayoutController& GetImpl( Dali::Toolkit::LayoutController& handle )
+{
+  DALI_ASSERT_ALWAYS(handle);
+  Dali::BaseObject& object = handle.GetBaseObject();
+  return static_cast<Internal::LayoutController&>(object);
+}
+
+inline const Internal::LayoutController& GetImpl( const Dali::Toolkit::LayoutController& handle )
+{
+  DALI_ASSERT_ALWAYS(handle);
+  const Dali::BaseObject& object = handle.GetBaseObject();
+  return static_cast<const Internal::LayoutController&>(object);
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUT_CONTROLLER_H
diff --git a/dali-toolkit/internal/layouting/layout-group-data-impl.cpp b/dali-toolkit/internal/layouting/layout-group-data-impl.cpp
new file mode 100644 (file)
index 0000000..f1d7fea
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali-toolkit/internal/layouting/layout-group-data-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+LayoutGroup::Impl::Impl()
+: mChildren(),
+  mNextLayoutId(1)
+{
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/layout-group-data-impl.h b/dali-toolkit/internal/layouting/layout-group-data-impl.h
new file mode 100644 (file)
index 0000000..f7e05e9
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUT_GROUP_DATA_IMPL_H_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUT_GROUP_DATA_IMPL_H_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 <vector>
+
+#include <dali-toolkit/devel-api/layouting/layout-base-impl.h>
+#include <dali-toolkit/internal/layouting/layout-base-data-impl.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class LayoutGroup::Impl
+{
+public:
+  Impl();
+
+public:
+  struct ChildLayout
+  {
+    LayoutBasePtr child;
+    Toolkit::LayoutGroup::LayoutId layoutId;
+  };
+
+  std::vector<ChildLayout> mChildren;
+  Toolkit::LayoutGroup::LayoutId mNextLayoutId;
+};
+
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_INTERNAL_LAYOUT_GROUP_DATA_IMPL_H_H
diff --git a/dali-toolkit/internal/layouting/vbox-layout-impl.cpp b/dali-toolkit/internal/layouting/vbox-layout-impl.cpp
new file mode 100644 (file)
index 0000000..ceb42c4
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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/vbox-layout-impl.h>
+
+//EXTERNAL HEADERS
+//INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/extents.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali-toolkit/devel-api/layouting/layout-base.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+VboxLayoutPtr VboxLayout::New()
+{
+  VboxLayoutPtr layout( new VboxLayout() );
+  return layout;
+}
+
+VboxLayout::VboxLayout()
+: LayoutGroup(),
+  mCellPadding( 0, 0 ),
+  mTotalLength( 0 )
+{
+}
+
+VboxLayout::~VboxLayout()
+{
+}
+
+void VboxLayout::DoInitialize()
+{
+}
+
+void VboxLayout::DoRegisterChildProperties( const std::string& containerType )
+{
+  auto typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( containerType );
+  if( typeInfo )
+  {
+    Property::IndexContainer indices;
+    typeInfo.GetChildPropertyIndices( indices );
+
+    if( std::find( indices.Begin(), indices.End(), Toolkit::VboxLayout::ChildProperty::WEIGHT ) ==
+        indices.End() )
+    {
+      ChildPropertyRegistration( typeInfo.GetName(), "weight", Toolkit::VboxLayout::ChildProperty::WEIGHT, Property::FLOAT );
+    }
+  }
+}
+
+void VboxLayout::OnChildAdd( LayoutBase& child )
+{
+  auto owner = child.GetOwner();
+  owner.SetProperty( Toolkit::VboxLayout::ChildProperty::WEIGHT, 1.0f );
+}
+
+void VboxLayout::SetCellPadding( LayoutSize size )
+{
+  mCellPadding = size;
+}
+
+LayoutSize VboxLayout::GetCellPadding()
+{
+  return mCellPadding;
+}
+
+
+void VboxLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+#if defined(DEBUG_ENABLED)
+  auto actor = Actor::DownCast(GetOwner());
+
+  std::ostringstream oss;
+  oss << "VboxLayout::OnMeasure  ";
+  if( actor )
+  {
+    oss << "Actor Id:" << actor.GetId() << " Name:" << actor.GetName() << "  ";
+  }
+  oss << "widthMeasureSpec:" << widthMeasureSpec << " heightMeasureSpec:" << heightMeasureSpec << std::endl;
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, oss.str().c_str() );
+#endif
+
+  auto widthMode = widthMeasureSpec.GetMode();
+
+  bool matchWidth = false;
+  bool allFillParent = true;
+  LayoutLength maxWidth = 0;
+  LayoutLength alternativeMaxWidth = 0;
+
+  struct
+  {
+    MeasuredSize::State widthState;
+    MeasuredSize::State heightState;
+  } childState = { MeasuredSize::State::MEASURED_SIZE_OK, MeasuredSize::State::MEASURED_SIZE_OK };
+
+  // measure children, and determine if further resolution is required
+  for( unsigned int i=0; i<GetChildCount(); ++i )
+  {
+    auto childLayout = GetChildAt( i );
+    if( childLayout )
+    {
+      auto childOwner = childLayout->GetOwner();
+      auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
+
+      MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, heightMeasureSpec, 0 );
+      auto childHeight = childLayout->GetMeasuredHeight();
+      auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
+      auto length = childHeight + LayoutLength::IntType(childMargin.top + childMargin.bottom );
+
+      auto cellPadding = i<GetChildCount()-1 ? mCellPadding.height : 0;
+      auto totalLength = mTotalLength;
+      mTotalLength = std::max( totalLength, totalLength + length + cellPadding);
+
+      bool matchWidthLocally = false;
+      if( widthMode != MeasureSpec::Mode::EXACTLY && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT )
+      {
+        // Will have to re-measure at least this child when we know exact height.
+        matchWidth = true;
+        matchWidthLocally = true;
+      }
+
+      auto marginWidth = LayoutLength( childMargin.start + childMargin.end );
+      auto childWidth = childLayout->GetMeasuredWidth() + marginWidth;
+
+      // was combineMeasuredStates()
+      if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
+      {
+        childState.widthState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
+      }
+      if( childLayout->GetMeasuredHeightAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
+      {
+        childState.heightState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
+      }
+
+      maxWidth = std::max( maxWidth, childWidth );
+      allFillParent = ( allFillParent && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT );
+      alternativeMaxWidth = std::max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
+    }
+  }
+
+  Extents padding = GetPadding();
+  mTotalLength += padding.top + padding.bottom;
+  auto heightSize = mTotalLength;
+  heightSize = std::max( heightSize, GetSuggestedMinimumHeight() );
+  MeasuredSize heightSizeAndState = ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK);
+  heightSize = heightSizeAndState.GetSize();
+
+  if( !allFillParent && widthMode != MeasureSpec::Mode::EXACTLY )
+  {
+    maxWidth = alternativeMaxWidth;
+  }
+  maxWidth += padding.start + padding.end;
+  maxWidth = std::max( maxWidth, GetSuggestedMinimumWidth() );
+
+  heightSizeAndState.SetState( childState.heightState );
+
+  SetMeasuredDimensions( ResolveSizeAndState( maxWidth, widthMeasureSpec, childState.widthState ),
+                         heightSizeAndState );
+
+  if( matchWidth )
+  {
+    ForceUniformWidth( GetChildCount(), heightMeasureSpec );
+  }
+}
+
+void VboxLayout::ForceUniformWidth( int count, MeasureSpec heightMeasureSpec )
+{
+  // Pretend that the linear layout has an exact size. This is the measured height of
+  // ourselves. The measured height should be the max height of the children, changed
+  // to accommodate the heightMeasureSpec from the parent
+  auto uniformMeasureSpec = MeasureSpec( GetMeasuredWidth(), MeasureSpec::Mode::EXACTLY );
+  for (int i = 0; i < count; ++i)
+  {
+    LayoutBasePtr childLayout = GetChildAt(i);
+    if( childLayout != nullptr )
+    {
+      auto childOwner = childLayout->GetOwner();
+      auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::WIDTH_SPECIFICATION );
+      auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION );
+
+      if( desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT )
+      {
+        // Temporarily force children to reuse their old measured height
+        int oldHeight = desiredHeight;
+        childOwner.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, childLayout->GetMeasuredHeight().mValue );
+
+        // Remeasure with new dimensions
+        MeasureChildWithMargins( childLayout, uniformMeasureSpec, 0, heightMeasureSpec, 0 );
+
+        childOwner.SetProperty( Toolkit::LayoutBase::ChildProperty::HEIGHT_SPECIFICATION, oldHeight );
+      }
+    }
+  }
+}
+
+void VboxLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+  auto owner = GetOwner();
+  Extents padding = GetPadding();
+
+  LayoutLength childTop( 0 );
+  LayoutLength childLeft( padding.start );
+
+  // Where bottom of child should go
+  auto width = right - left;
+
+  // Space available for child
+  auto childSpace = width - padding.start - padding.end;
+  auto count = GetChildCount();
+
+  for( unsigned int childIndex = 0; childIndex < count; childIndex++)
+  {
+    LayoutBasePtr childLayout = GetChildAt( childIndex );
+    if( childLayout != nullptr )
+    {
+      auto childWidth = childLayout->GetMeasuredWidth();
+      auto childHeight = childLayout->GetMeasuredHeight();
+
+      auto childOwner = childLayout->GetOwner();
+      auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
+
+      childTop += childMargin.top;
+      childLeft = ( childSpace - childWidth ) / 2 + childMargin.start - childMargin.end;
+
+      childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
+      childTop += childHeight + childMargin.bottom + mCellPadding.height;
+    }
+  }
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/layouting/vbox-layout-impl.h b/dali-toolkit/internal/layouting/vbox-layout-impl.h
new file mode 100644 (file)
index 0000000..e64bb16
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LAYOUTING_VBOX_LAYOUT_H
+#define DALI_TOOLKIT_INTERNAL_LAYOUTING_VBOX_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/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+#include <dali-toolkit/devel-api/layouting/vbox-layout.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class VboxLayout;
+using VboxLayoutPtr = IntrusivePtr<VboxLayout>;
+
+class VboxLayout final : public LayoutGroup
+{
+public:
+  static VboxLayoutPtr New();
+
+public:
+
+  /**
+   * Set the inter-cell padding
+   * @param[in] size The size of the inter-cell padding
+   */
+  void SetCellPadding( LayoutSize size );
+
+  /**
+   * Get the inter-cell padding
+   * @return The size of the inter-cell padding
+   */
+  LayoutSize GetCellPadding();
+
+protected:
+  /**
+   * Constructor
+   */
+  VboxLayout();
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~VboxLayout();
+
+  /**
+   * @copydoc LayoutBase::DoInitialize
+   */
+  virtual void DoInitialize() override;
+
+  /**
+   * @copydoc LayoutBase::DoRegisterChildProperties()
+   */
+  virtual void DoRegisterChildProperties( const std::string& containerType ) override;
+
+  /**
+   * @copydoc LayoutBase::OnChildAdd
+   */
+  virtual void OnChildAdd( LayoutBase& child ) override;
+
+  /**
+   * @copydoc LayoutBase::OnMeasure
+   */
+  virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) override;
+
+  /**
+   * @copydoc LayoutBase::OnLayout
+   */
+  virtual void OnLayout( bool changed, LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b ) override;
+
+private:
+  VboxLayout( const VboxLayout& other ) = delete;
+  VboxLayout& operator=( const VboxLayout& other ) = delete;
+
+  /**
+   * Apply a uniform width to the children
+   */
+  void ForceUniformWidth( int count, MeasureSpec heightMeasureSpec );
+
+private:
+  LayoutSize mCellPadding;
+  LayoutLength mTotalLength;
+};
+
+} // namespace Internal
+
+inline Internal::VboxLayout& GetImplementation( Dali::Toolkit::VboxLayout& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "VboxLayout handle is empty" );
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast<Internal::VboxLayout&>( object );
+}
+
+inline const Internal::VboxLayout& GetImplementation( const Dali::Toolkit::VboxLayout& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "VboxLayout handle is empty" );
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast<const Internal::VboxLayout&>( object );
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_LAYOUTING_VBOX_LAYOUT_H