2 * Copyright (c) 2021 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");
40 // Common callback function that is registered when AddChild is called.
41 // Calls MeasureNode which in turns calls the actual callback passed in AddChild not the common callback.
42 YGSize MeasureChild(YGNodeRef child, float width, YGMeasureMode measureModeWidth, float height, YGMeasureMode measureModeHeight)
44 DALI_LOG_INFO(gLogFilter, Debug::General, "MeasureChild\n");
45 // Get the Node from the YGNodeRef
46 Toolkit::Flex::Node* childNode = static_cast<Toolkit::Flex::Node*>(YGNodeGetContext(child));
48 YGSize childSize{1, 1}; // Initialise variable.
50 DALI_ASSERT_DEBUG(childNode);
52 // Call measure function assigned to this Node
53 Toolkit::Flex::SizeTuple nodeSize = childNode->MeasureNode(width, measureModeWidth, height, measureModeHeight);
54 childSize.width = nodeSize.width;
55 childSize.height = nodeSize.height;
56 DALI_LOG_INFO(gLogFilter, Debug::General, "MeasureChild, childNode valid %f,%f\n", childSize.width, childSize.height);
65 using NodePtr = std::unique_ptr<Node>;
67 using FlexNodeVector = std::vector<NodePtr>;
72 MeasureCallback mMeasureCallback;
73 WeakHandle<Dali::Actor> mActor;
74 FlexNodeVector mChildNodes;
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");
98 YGNodeFreeRecursive(mImpl->mYogaNode);
99 mImpl->mYogaNode = nullptr;
101 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Destructor() <<\n");
104 Node* 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.GetProperty<std::string>(Dali::Actor::Property::NAME).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.GetProperty<Vector2>(Actor::Property::MINIMUM_SIZE);
117 Vector2 maximumSize = child.GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE);
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 Node* result = childNode.get();
134 mImpl->mChildNodes.emplace_back(std::move(childNode));
142 void Node::RemoveChild(Actor child)
144 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RemoveChild child:[%s] from internal nodeCount[%d] childCount[%d]\n", child.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str(), YGNodeGetChildCount(mImpl->mYogaNode), mImpl->mChildNodes.size());
146 auto iterator = std::find_if(mImpl->mChildNodes.begin(), mImpl->mChildNodes.end(), [&child](NodePtr& childNode) { return childNode->mImpl->mActor.GetHandle() == child; });
148 if(iterator != mImpl->mChildNodes.end())
150 YGNodeRemoveChild(mImpl->mYogaNode, (*iterator)->mImpl->mYogaNode);
151 mImpl->mChildNodes.erase(iterator);
154 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RemoveChild internal nodeCount[%d] childCount[%d]\n", YGNodeGetChildCount(mImpl->mYogaNode), mImpl->mChildNodes.size());
157 SizeTuple Node::MeasureNode(float width, int widthMode, float height, int heightMode)
159 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MeasureNode\n");
161 // Execute callback registered with AddChild
162 Toolkit::Flex::SizeTuple nodeSize{8, 8}; // Default size set to 8,8 to aid bug detection.
163 if(mImpl->mMeasureCallback && mImpl->mActor.GetHandle())
165 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MeasureNode MeasureCallback executing on %s\n", mImpl->mActor.GetHandle().GetProperty<std::string>(Dali::Actor::Property::NAME).c_str());
166 mImpl->mMeasureCallback(mImpl->mActor.GetHandle(), width, widthMode, height, heightMode, &nodeSize);
168 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MeasureNode nodeSize width:%f height:%f\n", nodeSize.width, nodeSize.height);
172 void Node::CalculateLayout(float availableWidth, float availableHeight, bool isRTL)
174 DALI_LOG_INFO(gLogFilter, Debug::General, "CalculateLayout availableSize(%f,%f)\n", availableWidth, availableHeight);
175 YGNodeCalculateLayout(mImpl->mYogaNode, availableWidth, availableHeight, isRTL ? YGDirectionRTL : YGDirectionLTR);
178 Dali::Vector4 Node::GetNodeFrame(int index) const
180 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GetNodeFrame[%d]\n", index);
181 YGNodeRef childNode = YGNodeGetChild(mImpl->mYogaNode, index);
182 Dali::Vector4 frame = Vector4::ZERO;
185 frame.x = YGNodeLayoutGetLeft(childNode);
186 frame.y = YGNodeLayoutGetTop(childNode);
187 frame.z = frame.x + YGNodeLayoutGetWidth(childNode);
188 frame.w = frame.y + YGNodeLayoutGetHeight(childNode);
189 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GetNodeFrame Node index[%d] child ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n", index, childNode, frame.x, frame.y, frame.z, frame.w);
193 frame.x = YGNodeLayoutGetLeft(mImpl->mYogaNode);
194 frame.y = YGNodeLayoutGetTop(mImpl->mYogaNode);
195 frame.z = frame.x + YGNodeLayoutGetWidth(mImpl->mYogaNode);
196 frame.w = frame.y + YGNodeLayoutGetHeight(mImpl->mYogaNode);
197 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GetNodeFrame Root index[%d] root ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n", index, mImpl->mYogaNode, frame.x, frame.y, frame.z, frame.w);
202 void Node::SetFlexDirection(Dali::Toolkit::Flex::FlexDirection flexDirection)
204 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex direction[%d]\n", flexDirection);
206 YGNodeStyleSetFlexDirection(mImpl->mYogaNode, static_cast<YGFlexDirection>(flexDirection));
209 Dali::Toolkit::Flex::FlexDirection Node::GetFlexDirection() const
211 return static_cast<Dali::Toolkit::Flex::FlexDirection>(YGNodeStyleGetFlexDirection(mImpl->mYogaNode));
214 void Node::SetFlexJustification(Dali::Toolkit::Flex::Justification flexJustification)
216 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex justification[%d]\n", flexJustification)
218 YGNodeStyleSetJustifyContent(mImpl->mYogaNode, static_cast<YGJustify>(flexJustification));
221 Dali::Toolkit::Flex::Justification Node::GetFlexJustification() const
223 return static_cast<Dali::Toolkit::Flex::Justification>(YGNodeStyleGetJustifyContent(mImpl->mYogaNode));
226 Dali::Toolkit::Flex::WrapType Node::GetFlexWrap() const
228 return static_cast<Dali::Toolkit::Flex::WrapType>(YGNodeStyleGetFlexWrap(mImpl->mYogaNode));
231 void Node::SetFlexAlignment(Dali::Toolkit::Flex::Alignment flexAlignment)
233 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex alignment[%d]\n", flexAlignment)
235 YGNodeStyleSetAlignContent(mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment));
238 Dali::Toolkit::Flex::Alignment Node::GetFlexAlignment() const
240 return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignContent(mImpl->mYogaNode));
243 void Node::SetFlexItemsAlignment(Dali::Toolkit::Flex::Alignment flexAlignment)
245 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex items alignment[%d] on mYogaNode[%p]\n", flexAlignment, mImpl->mYogaNode)
247 YGNodeStyleSetAlignItems(mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment));
250 Dali::Toolkit::Flex::Alignment Node::GetFlexItemsAlignment() const
252 return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignItems(mImpl->mYogaNode));
255 void Node::SetFlexAlignmentSelf(Dali::Toolkit::Flex::Alignment flexAlignmentSelf)
257 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex alignment self [%d] on mYogaNode[%p]\n", flexAlignmentSelf, mImpl->mYogaNode)
259 YGNodeStyleSetAlignSelf(mImpl->mYogaNode, static_cast<YGAlign>(flexAlignmentSelf));
262 Dali::Toolkit::Flex::Alignment Node::GetFlexAlignmentSelf() const
264 return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignSelf(mImpl->mYogaNode));
267 void Node::SetFlexPositionType(Dali::Toolkit::Flex::PositionType flexPositionType)
269 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex position type [%d] on mYogaNode[%p]\n", flexPositionType, mImpl->mYogaNode)
271 YGNodeStyleSetPositionType(mImpl->mYogaNode, static_cast<YGPositionType>(flexPositionType));
274 Dali::Toolkit::Flex::PositionType Node::GetFlexPositionType() const
276 return static_cast<Dali::Toolkit::Flex::PositionType>(YGNodeStyleGetPositionType(mImpl->mYogaNode));
279 void Node::SetFlexAspectRatio(float flexAspectRatio)
281 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex aspect ratio [%d] on mYogaNode[%p]\n", flexAspectRatio, mImpl->mYogaNode)
283 YGNodeStyleSetAspectRatio(mImpl->mYogaNode, static_cast<float>(flexAspectRatio));
286 float Node::GetFlexAspectRatio() const
288 return static_cast<float>(YGNodeStyleGetAspectRatio(mImpl->mYogaNode));
291 void Node::SetFlexBasis(float flexBasis)
293 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex basis [%d] on mYogaNode[%p]\n", flexBasis, mImpl->mYogaNode)
295 YGNodeStyleSetFlexBasis(mImpl->mYogaNode, static_cast<float>(flexBasis));
298 float Node::GetFlexBasis() const
300 return static_cast<float>(YGNodeStyleGetFlexBasis(mImpl->mYogaNode).value);
303 void Node::SetFlexShrink(float flexShrink)
305 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex shrink [%d] on mYogaNode[%p]\n", flexShrink, mImpl->mYogaNode)
307 YGNodeStyleSetFlexShrink(mImpl->mYogaNode, static_cast<float>(flexShrink));
310 float Node::GetFlexShrink() const
312 return static_cast<float>(YGNodeStyleGetFlexShrink(mImpl->mYogaNode));
315 void Node::SetFlexGrow(float flexGrow)
317 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex grow [%d] on mYogaNode[%p]\n", flexGrow, mImpl->mYogaNode)
319 YGNodeStyleSetFlexGrow(mImpl->mYogaNode, static_cast<float>(flexGrow));
322 float Node::GetFlexGrow() const
324 return static_cast<float>(YGNodeStyleGetFlexGrow(mImpl->mYogaNode));
327 float Node::GetFlexWidth() const
329 float flexWidth = YGNodeLayoutGetWidth(mImpl->mYogaNode);
330 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] width[%f]\n", mImpl->mYogaNode, flexWidth)
335 float Node::GetFlexHeight() const
337 float flexHeight = YGNodeLayoutGetHeight(mImpl->mYogaNode);
338 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] height[%f]\n", mImpl->mYogaNode, flexHeight)
343 void Node::SetMargin(Extents margin)
345 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex margin\n")
347 YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeLeft, margin.start);
348 YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeTop, margin.top);
349 YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeRight, margin.end);
350 YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeBottom, margin.bottom);
353 void Node::SetPadding(Extents padding)
355 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set padding\n")
357 YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeLeft, padding.start);
358 YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeTop, padding.top);
359 YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeRight, padding.end);
360 YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeBottom, padding.bottom);
363 void Node::SetFlexWrap(Dali::Toolkit::Flex::WrapType wrapType)
365 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex wrap[%d] on mYogaNode[%p]\n", wrapType, mImpl->mYogaNode)
367 YGNodeStyleSetFlexWrap(mImpl->mYogaNode, static_cast<YGWrap>(wrapType));
371 } // namespace Toolkit