2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "flex-node.h"
21 #include <dali/integration-api/debug.h>
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/object/weak-handle.h>
26 #include <dali-toolkit/third-party/yoga/Yoga.h>
28 #if defined(DEBUG_ENABLED)
29 static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_FLEX" );
41 // Common callback function that is registered when AddChild is called.
42 // Calls MeasureNode which in turns calls the actual callback passed in AddChild not the common callback.
43 YGSize MeasureChild(YGNodeRef child, float width, YGMeasureMode measureModeWidth, float height, YGMeasureMode measureModeHeight)
45 DALI_LOG_INFO( gLogFilter, Debug::General, "MeasureChild\n" );
46 // Get the Node from the YGNodeRef
47 Toolkit::Flex::Node* childNode = static_cast<Toolkit::Flex::Node*>(YGNodeGetContext(child));
49 YGSize childSize{ 1, 1 }; // Initialise variable.
51 DALI_ASSERT_DEBUG( childNode );
53 // Call measure function assigned to this Node
54 Toolkit::Flex::SizeTuple nodeSize = childNode->MeasureNode( width, measureModeWidth, height, measureModeHeight );
55 childSize.width = nodeSize.width;
56 childSize.height = nodeSize.height;
57 DALI_LOG_INFO( gLogFilter, Debug::General, "MeasureChild, childNode valid %f,%f\n", childSize.width, childSize.height );
66 using NodePtr = std::unique_ptr<Node>;
68 using FlexNodeVector = std::vector< NodePtr>;
73 MeasureCallback mMeasureCallback;
74 WeakHandle< Dali::Actor > mActor;
75 FlexNodeVector mChildNodes;
78 Node::Node() : mImpl( new Impl )
80 mImpl->mYogaNode = YGNodeNew();
81 YGNodeSetContext( mImpl->mYogaNode, this );
82 mImpl->mMeasureCallback = NULL;
83 DALI_LOG_INFO( gLogFilter, Debug::General, "Node() Context [%p] set to mYogaNode[%p]\n", this, mImpl->mYogaNode );
86 YGNodeStyleSetFlexDirection( mImpl->mYogaNode, YGFlexDirectionColumn );
87 YGNodeStyleSetFlexWrap( mImpl->mYogaNode, YGWrapNoWrap );
88 YGNodeStyleSetJustifyContent( mImpl->mYogaNode, YGJustifyFlexStart );
89 YGNodeStyleSetAlignContent( mImpl->mYogaNode, YGAlignFlexStart );
90 YGNodeStyleSetAlignItems( mImpl->mYogaNode, YGAlignFlexStart );
95 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destructor() >> \n");
96 if( mImpl->mYogaNode )
98 YGNodeFreeRecursive( mImpl->mYogaNode );
99 mImpl->mYogaNode = nullptr;
101 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destructor() <<\n");
104 void Node::AddChild( Actor child, Extents margin, MeasureCallback measureFunction, int index )
108 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddChild[%s] to node[%p] at index:%d\n", child.GetName().c_str(), mImpl->mYogaNode, index );
110 NodePtr childNode( new Node() );
112 // Store measure function passed in so can call it when the MeasureChild function is called.
113 childNode->mImpl->mMeasureCallback = measureFunction;
115 childNode->mImpl->mActor = child;
116 Vector2 minumumSize = child.GetMinimumSize();
117 Vector2 maximumSize = child.GetMaximumSize();
119 YGNodeStyleSetMaxWidth( childNode->mImpl->mYogaNode, maximumSize.width );
120 YGNodeStyleSetMaxHeight( childNode->mImpl->mYogaNode, maximumSize.height );
121 YGNodeStyleSetMinWidth( childNode->mImpl->mYogaNode, minumumSize.width );
122 YGNodeStyleSetMinHeight( childNode->mImpl->mYogaNode, minumumSize.height );
124 YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeLeft, margin.start );
125 YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeTop, margin.top );
126 YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeRight, margin.end );
127 YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeBottom, margin.bottom );
129 YGNodeSetMeasureFunc( childNode->mImpl->mYogaNode, &MeasureChild );
131 YGNodeInsertChild( mImpl->mYogaNode, childNode->mImpl->mYogaNode, index );
133 mImpl->mChildNodes.emplace_back( std::move(childNode) );
137 void Node::RemoveChild( Actor child )
139 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RemoveChild child:[%s] from internal nodeCount[%d] childCount[%d]\n", child.GetName().c_str(), YGNodeGetChildCount( mImpl->mYogaNode ), mImpl->mChildNodes.size() );
141 auto iterator = std::find_if( mImpl->mChildNodes.begin(),mImpl->mChildNodes.end(),
142 [&child]( NodePtr& childNode ){ return childNode->mImpl->mActor.GetHandle() == child;});
144 if( iterator != mImpl->mChildNodes.end() )
146 YGNodeRemoveChild( mImpl->mYogaNode, (*iterator)->mImpl->mYogaNode );
147 mImpl->mChildNodes.erase(iterator);
150 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RemoveChild internal nodeCount[%d] childCount[%d]\n", YGNodeGetChildCount( mImpl->mYogaNode ), mImpl->mChildNodes.size() );
153 SizeTuple Node::MeasureNode( float width, int widthMode, float height, int heightMode)
155 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode\n" );
157 // Execute callback registered with AddChild
158 Toolkit::Flex::SizeTuple nodeSize{8,8}; // Default size set to 8,8 to aid bug detection.
159 if( mImpl->mMeasureCallback && mImpl->mActor.GetHandle() )
161 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode MeasureCallback executing on %s\n", mImpl->mActor.GetHandle().GetName().c_str() );
162 nodeSize = mImpl->mMeasureCallback( mImpl->mActor.GetHandle(), width, widthMode, height, heightMode );
164 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode nodeSize width:%f height:%f\n", nodeSize.width, nodeSize.height );
168 void Node::CalculateLayout(float availableWidth, float availableHeight, bool isRTL)
170 DALI_LOG_INFO( gLogFilter, Debug::General, "CalculateLayout availableSize(%f,%f)\n", availableWidth, availableHeight );
171 YGNodeCalculateLayout( mImpl->mYogaNode, availableWidth, availableHeight, isRTL ? YGDirectionRTL : YGDirectionLTR );
174 Dali::Vector4 Node::GetNodeFrame( int index ) const
176 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame[%d]\n", index );
177 YGNodeRef childNode = YGNodeGetChild( mImpl->mYogaNode, index );
178 Dali::Vector4 frame = Vector4::ZERO;
181 frame.x = YGNodeLayoutGetLeft( childNode );
182 frame.y = YGNodeLayoutGetTop( childNode );
183 frame.z = frame.x + YGNodeLayoutGetWidth( childNode );
184 frame.w = frame.y + YGNodeLayoutGetHeight( childNode );
185 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame Node index[%d] child ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n",
186 index, childNode, frame.x , frame.y, frame.z, frame.w);
190 frame.x = YGNodeLayoutGetLeft( mImpl->mYogaNode );
191 frame.y = YGNodeLayoutGetTop( mImpl->mYogaNode );
192 frame.z = frame.x + YGNodeLayoutGetWidth( mImpl->mYogaNode );
193 frame.w = frame.y + YGNodeLayoutGetHeight( mImpl->mYogaNode );
194 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame Root index[%d] root ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n",
195 index, mImpl->mYogaNode, frame.x , frame.y, frame.z, frame.w);
200 void Node::SetFlexDirection( Dali::Toolkit::Flex::FlexDirection flexDirection )
202 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex direction[%d]\n", flexDirection );
204 YGNodeStyleSetFlexDirection( mImpl->mYogaNode, static_cast<YGFlexDirection>(flexDirection) );
207 Dali::Toolkit::Flex::FlexDirection Node::GetFlexDirection() const
209 return static_cast<Dali::Toolkit::Flex::FlexDirection>(YGNodeStyleGetFlexDirection( mImpl->mYogaNode ));
212 void Node::SetFlexJustification( Dali::Toolkit::Flex::Justification flexJustification )
214 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex justification[%d]\n", flexJustification )
216 YGNodeStyleSetJustifyContent( mImpl->mYogaNode, static_cast<YGJustify>(flexJustification) );
219 Dali::Toolkit::Flex::Justification Node::GetFlexJustification() const
221 return static_cast<Dali::Toolkit::Flex::Justification>(YGNodeStyleGetJustifyContent( mImpl->mYogaNode ));
224 Dali::Toolkit::Flex::WrapType Node::GetFlexWrap() const
226 return static_cast<Dali::Toolkit::Flex::WrapType>(YGNodeStyleGetFlexWrap( mImpl->mYogaNode ));
229 void Node::SetFlexAlignment(Dali::Toolkit::Flex::Alignment flexAlignment )
231 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex alignment[%d]\n", flexAlignment )
233 YGNodeStyleSetAlignContent( mImpl->mYogaNode , static_cast<YGAlign>(flexAlignment) );
236 Dali::Toolkit::Flex::Alignment Node::GetFlexAlignment() const
238 return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignContent( mImpl->mYogaNode ));
241 void Node::SetFlexItemsAlignment(Dali::Toolkit::Flex::Alignment flexAlignment )
243 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex items alignment[%d] on mYogaNode[%p]\n", flexAlignment, mImpl->mYogaNode )
245 YGNodeStyleSetAlignItems( mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment) );
248 Dali::Toolkit::Flex::Alignment Node::GetFlexItemsAlignment() const
250 return static_cast<Dali::Toolkit::Flex::Alignment>( YGNodeStyleGetAlignItems( mImpl->mYogaNode ));
253 float Node::GetFlexWidth() const
255 float flexWidth = YGNodeLayoutGetWidth( mImpl->mYogaNode );
256 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] width[%f]\n", mImpl->mYogaNode, flexWidth)
261 float Node::GetFlexHeight() const
263 float flexHeight = YGNodeLayoutGetHeight( mImpl->mYogaNode );
264 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] height[%f]\n", mImpl->mYogaNode, flexHeight)
269 void Node::SetMargin( Extents margin )
271 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex margin\n")
273 YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeLeft, margin.start );
274 YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeTop, margin.top );
275 YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeRight, margin.end );
276 YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeBottom, margin.bottom );
279 void Node::SetPadding( Extents padding )
281 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set padding\n")
283 YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeLeft, padding.start );
284 YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeTop, padding.top );
285 YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeRight, padding.end );
286 YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeBottom, padding.bottom );
289 void Node::SetFlexWrap( Dali::Toolkit::Flex::WrapType wrapType )
291 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex wrap[%d] on mYogaNode[%p]\n", wrapType, mImpl->mYogaNode )
293 YGNodeStyleSetFlexWrap( mImpl->mYogaNode, static_cast<YGWrap>(wrapType) );
297 } // namespace Toolkit