# Append list of test harness files (Won't get parsed for test cases)
LIST(APPEND TC_SOURCES
+ custom-layout.cpp
+ custom-layout-impl.cpp
dali-toolkit-test-utils/toolkit-adaptor.cpp
dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
dali-toolkit-test-utils/toolkit-application.cpp
--- /dev/null
+/*
+ * 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 "custom-layout-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+namespace Test
+{
+
+namespace Internal
+{
+
+using Dali::Actor;
+using Dali::Toolkit::MeasuredSize;
+
+CustomLayoutPtr CustomLayout::New()
+{
+ CustomLayoutPtr layout( new CustomLayout() );
+ return layout;
+}
+
+void CustomLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+ auto accumulatedWidth = 0;
+ auto maxHeight = 0;
+
+ // In this layout we will:
+ // Measuring the layout with the children in a horizontal configuration, one after another
+ // Set the required width to be the accumulated width of our children
+ // Set the required height to be the maximum height of any of our children
+
+ for( unsigned int i=0; i<GetChildCount(); ++i )
+ {
+ auto childLayout = GetChildAt( i );
+ if( childLayout )
+ {
+ MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
+ accumulatedWidth += childLayout->GetMeasuredWidth();
+ maxHeight = std::max( childLayout->GetMeasuredHeight().mValue, maxHeight );
+ }
+ }
+
+ // Finally, call this method to set the dimensions we would like
+ SetMeasuredDimensions( MeasuredSize( accumulatedWidth ), MeasuredSize( maxHeight ) );
+}
+
+void CustomLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+ LayoutLength childTop( 0 );
+ LayoutLength childLeft( 0 );
+
+ // We want to vertically align the children to the middle
+ auto height = bottom - top;
+ auto middle = height / 2;
+
+ auto owner = GetOwner();
+ auto actor = Actor::DownCast(owner);
+
+ // Horizontally align the children to the left
+ int count = actor.GetChildCount();
+ int currentLeft = 0;
+
+ for( int i = 0; i < count; i++)
+ {
+ Dali::Toolkit::Control child = Dali::Toolkit::Control::DownCast( actor.GetChildAt( i ) );
+ if( !child )
+ {
+ continue;
+ }
+
+ Dali::Toolkit::LayoutItem childLayout = Dali::Toolkit::DevelControl::GetLayout( child );
+ if( childLayout )
+ {
+ Dali::Toolkit::Internal::LayoutItem& childLayoutImpl = GetImplementation( childLayout );
+
+ auto childWidth = childLayoutImpl.GetMeasuredWidth();
+ auto childHeight = childLayoutImpl.GetMeasuredHeight();
+
+ childTop = middle - (childHeight / 2);
+ childLayoutImpl.Layout( currentLeft, childTop, currentLeft + childWidth, childTop + childHeight );
+ currentLeft += childWidth;
+ }
+ }
+}
+
+} // namespace Internal
+
+} // namespace Test
--- /dev/null
+#ifndef TEST_INTERNAL_CUSTOM_LAYOUT_H
+#define TEST_INTERNAL_CUSTOM_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali-toolkit/devel-api/layouting/layout-group-impl.h>
+
+// INTERNAL INCLUDES
+#include "custom-layout.h"
+
+namespace Test
+{
+
+namespace Internal
+{
+
+using Dali::Toolkit::MeasureSpec;
+using Dali::Toolkit::LayoutLength;
+
+class CustomLayout;
+using CustomLayoutPtr = Dali::IntrusivePtr< CustomLayout >;
+
+/**
+ * @brief The implementation of our custom layout.
+ *
+ * Here we will override the methods that we require to mimic a very simple horizontal layout.
+ */
+class CustomLayout final : public Dali::Toolkit::Internal::LayoutGroup
+{
+public:
+
+ /**
+ * @brief Create a new CustomLayout object.
+ * @return An intrusive pointer to the created CustomLayout object
+ */
+ static CustomLayoutPtr New();
+
+ // Movable but not copyable
+ CustomLayout( const CustomLayout& other ) = delete;
+ CustomLayout& operator=( const CustomLayout& ) = delete;
+ CustomLayout( CustomLayout&& other ) = default;
+ CustomLayout& operator=( CustomLayout&& other ) = default;
+
+private:
+
+ /**
+ * @brief Default Constructor
+ */
+ CustomLayout() = default;
+
+ /**
+ * Virtual Destructor
+ */
+ virtual ~CustomLayout() = default;
+
+ /**
+ * @copydoc LayoutItem::OnMeasure
+ *
+ * Overriding this method so that we can calculate the size we require using our children's sizes
+ */
+ virtual void OnMeasure( MeasureSpec widthMeasureSpec, Dali::Toolkit::MeasureSpec heightMeasureSpec ) override;
+
+ /**
+ * @copydoc LayoutItem::OnLayout
+ *
+ * Overriding this method so that we can layout our children as required.
+ */
+ virtual void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom ) override;
+
+};
+
+} // namespace Internal
+
+inline Internal::CustomLayout& GetImplementation( Test::CustomLayout& handle )
+{
+ DALI_ASSERT_ALWAYS( handle && "CustomLayout handle is empty" );
+ Dali::BaseObject& object = handle.GetBaseObject();
+ return static_cast<Internal::CustomLayout&>( object );
+}
+
+inline const Internal::CustomLayout& GetImplementation( const Test::CustomLayout& handle )
+{
+ DALI_ASSERT_ALWAYS( handle && "CustomLayout handle is empty" );
+ const Dali::BaseObject& object = handle.GetBaseObject();
+ return static_cast<const Internal::CustomLayout&>( object );
+}
+
+} // namespace Test
+
+#endif // TEST_INTERNAL_CUSTOM_LAYOUT_H
--- /dev/null
+/*
+ * 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 "custom-layout.h"
+
+// INTERNAL HEADERS
+#include "custom-layout-impl.h"
+
+namespace Test
+{
+
+CustomLayout CustomLayout::New()
+{
+ Internal::CustomLayoutPtr internal = Internal::CustomLayout::New();
+ return CustomLayout( internal.Get() );
+}
+
+CustomLayout CustomLayout::DownCast( BaseHandle handle )
+{
+ return CustomLayout( dynamic_cast< Test::Internal::CustomLayout* >( handle.GetObjectPtr() ) );
+}
+
+CustomLayout::CustomLayout( Internal::CustomLayout* object )
+: Dali::Toolkit::LayoutGroup( object )
+{
+}
+
+void CustomLayout::RequestLayout()
+{
+ GetImplementation( *this ).RequestLayout();
+}
+} // namespace Test
--- /dev/null
+#ifndef TEST_CUSTOM_LAYOUT_H
+#define TEST_CUSTOM_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali-toolkit/devel-api/layouting/layout-group.h>
+
+namespace Test
+{
+
+namespace Internal
+{
+class CustomLayout;
+}
+
+/**
+ * @brief This is the handle class to a very simple Custom Layout.
+ *
+ * This class lays out its children horizontally in a very simple manner.
+ */
+class CustomLayout : public Dali::Toolkit::LayoutGroup
+{
+public:
+
+ /**
+ * @brief Creates an uninitialized CustomLayout handle.
+ *
+ * Initialize it using CustomLayout::New().
+ * Calling member functions with an uninitialized handle is not allowed.
+ */
+ CustomLayout() = default;
+
+ /**
+ * @brief Creates a CustomLayout object.
+ */
+ static CustomLayout New();
+
+
+ /**
+ * @brief Default destructor.
+ *
+ * This is non-virtual, since derived Handle types must not contain data or virtual methods
+ */
+ ~CustomLayout() = default;
+
+ /**
+ * @brief Copy constructor
+ */
+ CustomLayout( const CustomLayout& ) = default;
+
+ /**
+ * @brief Assigment operator
+ */
+ CustomLayout& operator=( const CustomLayout& ) = default;
+
+ /**
+ * @brief Move constructor
+ */
+ CustomLayout( CustomLayout&& ) = default;
+
+ /**
+ * @brief Movable assignment operator
+ */
+ CustomLayout& operator=( CustomLayout&& ) = default;
+
+ /**
+ * @brief Downcasts a handle to a CustomLayout handle.
+ *
+ * If handle points to a CustomLayout, the downcast produces a valid handle.
+ * If not, the returned handle is left uninitialized.
+
+ * @param[in] handle to an object
+ * @return Handle to a CustomLayout or an uninitialized handle
+ */
+ static CustomLayout DownCast( BaseHandle handle );
+
+ void RequestLayout();
+
+public: // Not intended for application developers
+
+ /// @cond internal
+ /**
+ * @brief This constructor is used by CustomLayout::New() methods.
+ *
+ * @param[in] actor A pointer to a newly allocated Dali resource
+ */
+ explicit CustomLayout( Internal::CustomLayout* body );
+ /// @endcond
+};
+
+} // namespace Test
+
+#endif // TEST_CUSTOM_LAYOUT_H
#include <dali-toolkit/devel-api/layouting/absolute-layout.h>
#include <dali-toolkit/devel-api/layouting/linear-layout.h>
+#include <../custom-layout.h>
+
#include <layout-utils.h>
using namespace Dali;
END_TEST;
}
+
+
+
+int UtcDaliLayouting_RelayoutOnChildOrderChanged(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliLayouting_RelayoutOnChildOrderChanged");
+ tet_infoline(" Test that if the sibling order changes, the container is re-laid out automatically");
+
+ Stage stage = Stage::GetCurrent();
+
+ auto hbox = Control::New();
+ auto hboxLayout = Test::CustomLayout::New();
+ 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( 40.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[2].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 100.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 180.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 );
+
+ controls[0].RaiseToTop(); // 0->3; 1, 2, 3, 0
+ controls[2].Lower(); // 2->1; 2, 1, 3, 0
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[2].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( 80.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[3].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 140.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 240.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_HboxLayout_TargetSize(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliLayouting_HboxLayout07 - Set target size on leaf");
+
+ Stage stage = Stage::GetCurrent();
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetName( "HBox");
+
+ std::vector< Control > controls;
+ controls.push_back( CreateLeafControl( 40, 40 ) );
+ for( auto&& iter : controls )
+ {
+ iter.SetSize( 100, 100 );
+ 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 from left to right.
+ // hbox left justifies elements
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 100.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
DevelActor::ChildAddedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildAddedToOwner );
DevelActor::ChildRemovedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildRemovedFromOwner );
+ DevelActor::ChildOrderChangedSignal( control ).Connect( mSlotDelegate, &LayoutGroup::ChildOrderChanged );
DevelHandle::PropertySetSignal( control ).Connect( mSlotDelegate, &LayoutGroup::OnOwnerPropertySet );
if( control.GetParent() )
{
LayoutItemPtr childLayout;
Toolkit::Control control = Toolkit::Control::DownCast( child );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner(%s)\n", control.GetName().c_str() );
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner control(%s)\n", control?control.GetName().c_str():"Invalid" );
if( control ) // Can only support adding Controls, not Actors to layout
{
#endif
childControlDataImpl.SetLayout( *childLayout.Get() );
+ Vector3 size = child.GetTargetSize();
+ // If the size of the control is set explicitly make sure that the control size
+ // stays the same after the layout except it is over written with match parent specs.
+ if ( size.x != 0 )
+ {
+ childLayout->SetMinimumWidth( size.x );
+ }
+
+ if ( size.y != 0 )
+ {
+ childLayout->SetMinimumHeight( size.y );
+ }
// Default layout data will be generated by Add().
}
else
}
}
+void LayoutGroup::ChildOrderChanged()
+{
+ RequestLayout();
+ // Force Children to be relaid out:
+ for( auto&& child : mImpl->mChildren )
+ {
+ child.child->SetLayoutRequested();
+ }
+}
+
void LayoutGroup::OnOwnerPropertySet( Handle& handle, Property::Index index, Property::Value value )
{
DALI_LOG_INFO( gLogFilter, Debug::Concise, "LayoutGroup::OnOwnerPropertySet\n");
void ChildRemovedFromOwner( Actor child );
/**
+ * Callback when child order is changed
+ */
+ void ChildOrderChanged();
+
+ /**
* 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 );
return x==rhs.x && y==rhs.y;
}
+ bool operator!=( const LayoutSize& rhs )
+ {
+ return !( *this==rhs );
+ }
+
union
{
LayoutLength::IntType x;
void LinearLayout::SetCellPadding( LayoutSize size )
{
GetImplementation(*this).SetCellPadding( size );
- GetImplementation(*this).RequestLayout();
}
LayoutSize LinearLayout::GetCellPadding()
{
return GetImplementation(*this).GetCellPadding();
- GetImplementation(*this).RequestLayout();
}
void LinearLayout::SetOrientation( LinearLayout::Orientation orientation )
{
GetImplementation(*this).SetOrientation( orientation );
- GetImplementation(*this).RequestLayout();
}
LinearLayout::Orientation LinearLayout::GetOrientation()
{
return GetImplementation(*this).GetOrientation();
- GetImplementation(*this).RequestLayout();
}
LinearLayout::LinearLayout( Dali::Toolkit::Internal::LinearLayout* object )
YGNodeStyleSetMaxWidth( mRoot, width );
}
- if (heightMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY)
+ if ( heightMeasureSpec.GetMode() == MeasureSpec::Mode::EXACTLY )
{
height = heightMeasureSpec.GetSize();
YGNodeStyleSetHeight( mRoot, height );
}
- else if (widthMeasureSpec.GetMode() == MeasureSpec::Mode::AT_MOST)
+ else if ( heightMeasureSpec.GetMode() == MeasureSpec::Mode::AT_MOST )
{
height = heightMeasureSpec.GetSize();
YGNodeStyleSetMaxHeight( mRoot, height );
if( desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
{
- if( innerWidth != YGUndefined)
+ if( innerHeight != YGUndefined)
{
desiredHeight = innerHeight;
}
void LinearLayout::SetCellPadding( LayoutSize size )
{
- mCellPadding = size;
+ if ( mCellPadding != size )
+ {
+ mCellPadding = size;
+ RequestLayout();
+ }
}
LayoutSize LinearLayout::GetCellPadding()
void LinearLayout::SetOrientation( Dali::Toolkit::LinearLayout::Orientation orientation )
{
- mOrientation = orientation;
+ if ( mOrientation != orientation )
+ {
+ mOrientation = orientation;
+ RequestLayout();
+ }
}
Dali::Toolkit::LinearLayout::Orientation LinearLayout::GetOrientation()
const unsigned int TOOLKIT_MAJOR_VERSION = 1;
const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 29;
+const unsigned int TOOLKIT_MICRO_VERSION = 30;
const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali-toolkit
Summary: Dali 3D engine Toolkit
-Version: 1.3.29
+Version: 1.3.30
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT