Setting layout already in use 12/192012/4
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Fri, 26 Oct 2018 16:30:14 +0000 (17:30 +0100)
committerAgnelo Vaz <agnelo.vaz@samsung.com>
Mon, 29 Oct 2018 16:14:18 +0000 (16:14 +0000)
If a control is using a layout and that layout is then
set to another control the original control gets a BinLayout.

Change-Id: I482d00239eaec765126b3554b982c8e86ab135f6

automated-tests/src/dali-toolkit/utc-Dali-LayoutingSettingAndRemoval.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp

index b55afd6..7e12c1c 100644 (file)
@@ -233,4 +233,85 @@ int UtcDaliLayoutingSettingAndRemoval_RemoveLayoutFromHbox(void)
   DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
 
   END_TEST;
-}
\ No newline at end of file
+}
+
+int UtcDaliLayouting_SetLayoutAlreadyInUse(void)
+{
+  /*
+  1 ControlA (LinearLayoutA)
+  2 Add 3 children
+
+  3 ControlB (LinearLayoutA)
+  4 Add 4 children
+
+  Test number of children in each control/layout
+
+  LinearLayoutA should now have 4 children
+
+  ControlB should have 4 children too
+  ControlA should have 3 children.
+
+  */
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliLayouting_SetLayoutAlreadyInUse - Set layout belonging to controlA to controlB");
+
+  Stage stage = Stage::GetCurrent();
+
+  auto rootControl = Control::New();
+  auto absoluteLayout = AbsoluteLayout::New();
+  DevelControl::SetLayout( rootControl, absoluteLayout );
+  rootControl.SetName( "AbsoluteLayout" );
+  stage.Add( rootControl );
+
+  auto controlA = Control::New();
+  auto hboxLayout = LinearLayout::New();
+  controlA.SetName( "controlA");
+
+  rootControl.Add( controlA );
+
+  DevelControl::SetLayout( controlA, hboxLayout );
+
+  // Add child controls
+  std::vector< Control > controls;
+  controls.push_back( CreateLeafControl( 100, 100 ) );  // 0
+  controls.push_back( CreateLeafControl( 100, 100 ) );  // 1
+  controls.push_back( CreateLeafControl( 100, 100 ) );  // 2
+
+  for( auto&& iter : controls )
+  {
+    controlA.Add( iter );
+  }
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("SetLayout to another control");
+
+  auto controlB = Control::New();
+  controlB.SetName( "controlB");
+
+  std::vector< Control > moreControls;
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 0
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 1
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 3
+  moreControls.push_back( CreateLeafControl( 100, 100 ) );  // 4
+
+  for( auto&& iter : moreControls )
+  {
+    controlB.Add( iter );
+  }
+
+  DevelControl::SetLayout( controlB, hboxLayout );  // Set hboxLayout used by ControlA to ControlB
+
+  // Ensure layouting happens
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Get number of children in each control's layout");
+  DALI_TEST_EQUALS( ( LayoutGroup::DownCast( DevelControl::GetLayout( controlA ) ) ).GetChildCount(), 3 , TEST_LOCATION );
+  DALI_TEST_EQUALS( ( LayoutGroup::DownCast( DevelControl::GetLayout( controlB ) ) ).GetChildCount(), 4 , TEST_LOCATION );
+
+  END_TEST;
+}
index 52a0d4a..404a9ec 100755 (executable)
@@ -291,6 +291,9 @@ DALI_TOOLKIT_API Toolkit::LayoutItem GetLayout( Control control );
  * @param[in] layout Pointer to the layout
  * @note Providing an empty layout will remove the current layout and
  *       replace it with a BinLayout.
+ *       Setting a layout that has already been set will result in the
+ *       original control becoming a BinLayout.  Two Controls can not share
+ *       the same layout.
  */
 DALI_TOOLKIT_API void SetLayout( Internal::Control& control, Toolkit::LayoutItem layout );
 
index c5af35e..a8387ee 100755 (executable)
@@ -1441,15 +1441,35 @@ Toolkit::Internal::LayoutItemPtr Control::Impl::GetLayout() const
 
 void Control::Impl::SetLayout( Toolkit::Internal::LayoutItem& layout )
 {
-  DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout control:%s  existing layout:%s\n",
+  DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout control:%s  replacing existing layout:%s\n",
                                    mControlImpl.Self().GetName().c_str(),
                                    mLayout?"true":"false" );
+  // Check if layout already has an owner.
+  auto control = Toolkit::Control::DownCast( layout.GetOwner() );
+  if ( control )
+  {
+    // If the owner is not this control then the owning control can no longer own it.
+    Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
+    if( control != handle )
+    {
+      DALI_LOG_INFO( gLogFilterLayout, Debug::Verbose, "Control::SetLayout Layout already in use, %s will now have a BinLayout\n",
+                                                        control.GetName().c_str() );
+      Toolkit::BinLayout binLayout = Toolkit::BinLayout::New();
+      // Previous owner of the layout gets a BinLayout instead of the layout.
+      DevelControl::SetLayout( control, binLayout ) ;
+    }
+    else
+    {
+      return; // layout is already set to this control.
+    }
+  }
 
   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.