Delete YGNode only root of Flex::Node
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / layouting / flex-node.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 //CLASS HEADER
18 #include "flex-node.h"
19
20 //EXTERNAL INCLUDES
21 #include <dali/integration-api/debug.h>
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/object/weak-handle.h>
24
25 //INTERNAL INCLUDES
26 #include <dali-toolkit/third-party/yoga/Yoga.h>
27
28 #if defined(DEBUG_ENABLED)
29 static Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FLEX");
30 #endif
31
32 namespace Dali
33 {
34 namespace Toolkit
35 {
36 namespace Flex
37 {
38 namespace
39 {
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)
43 {
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));
47
48   YGSize childSize{1, 1}; // Initialise variable.
49
50   DALI_ASSERT_DEBUG(childNode);
51
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);
57
58   return childSize;
59 }
60
61 } // namespace
62
63 struct Node;
64
65 using NodePtr = std::unique_ptr<Node>;
66
67 using FlexNodeVector = std::vector<NodePtr>;
68
69 struct Node::Impl
70 {
71   YGNodeRef               mYogaNode;
72   MeasureCallback         mMeasureCallback;
73   WeakHandle<Dali::Actor> mActor;
74   FlexNodeVector          mChildNodes;
75 };
76
77 Node::Node()
78 : mImpl(new Impl)
79 {
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);
84
85   // Set default style
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);
91 }
92
93 Node::~Node()
94 {
95   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Destructor() >> \n");
96   // Destruct child Flex::Node first
97   mImpl->mChildNodes.clear();
98
99   if(mImpl->mYogaNode)
100   {
101     YGNodeFree(mImpl->mYogaNode);
102     mImpl->mYogaNode = nullptr;
103   }
104   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Destructor() <<\n");
105 }
106
107 Node* Node::AddChild(Actor child, Extents margin, MeasureCallback measureFunction, int index)
108 {
109   if(child)
110   {
111     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);
112
113     NodePtr childNode(new Node());
114
115     // Store measure function passed in so can call it when the MeasureChild function is called.
116     childNode->mImpl->mMeasureCallback = measureFunction;
117
118     childNode->mImpl->mActor = child;
119     Vector2 minumumSize      = child.GetProperty<Vector2>(Actor::Property::MINIMUM_SIZE);
120     Vector2 maximumSize      = child.GetProperty<Vector2>(Actor::Property::MAXIMUM_SIZE);
121
122     YGNodeStyleSetMaxWidth(childNode->mImpl->mYogaNode, maximumSize.width);
123     YGNodeStyleSetMaxHeight(childNode->mImpl->mYogaNode, maximumSize.height);
124     YGNodeStyleSetMinWidth(childNode->mImpl->mYogaNode, minumumSize.width);
125     YGNodeStyleSetMinHeight(childNode->mImpl->mYogaNode, minumumSize.height);
126
127     YGNodeStyleSetMargin(childNode->mImpl->mYogaNode, YGEdgeLeft, margin.start);
128     YGNodeStyleSetMargin(childNode->mImpl->mYogaNode, YGEdgeTop, margin.top);
129     YGNodeStyleSetMargin(childNode->mImpl->mYogaNode, YGEdgeRight, margin.end);
130     YGNodeStyleSetMargin(childNode->mImpl->mYogaNode, YGEdgeBottom, margin.bottom);
131
132     YGNodeSetMeasureFunc(childNode->mImpl->mYogaNode, &MeasureChild);
133
134     YGNodeInsertChild(mImpl->mYogaNode, childNode->mImpl->mYogaNode, index);
135
136     Node* result = childNode.get();
137     mImpl->mChildNodes.emplace_back(std::move(childNode));
138
139     return result;
140     ;
141   }
142   return nullptr;
143 }
144
145 void Node::RemoveChild(Actor child)
146 {
147   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());
148
149   auto iterator = std::find_if(mImpl->mChildNodes.begin(), mImpl->mChildNodes.end(), [&child](NodePtr& childNode) { return childNode->mImpl->mActor.GetHandle() == child; });
150
151   if(iterator != mImpl->mChildNodes.end())
152   {
153     YGNodeRemoveChild(mImpl->mYogaNode, (*iterator)->mImpl->mYogaNode);
154     mImpl->mChildNodes.erase(iterator);
155   }
156
157   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RemoveChild internal nodeCount[%d] childCount[%d]\n", YGNodeGetChildCount(mImpl->mYogaNode), mImpl->mChildNodes.size());
158 }
159
160 SizeTuple Node::MeasureNode(float width, int widthMode, float height, int heightMode)
161 {
162   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MeasureNode\n");
163
164   // Execute callback registered with AddChild
165   Toolkit::Flex::SizeTuple nodeSize{8, 8}; // Default size set to 8,8 to aid bug detection.
166   if(mImpl->mMeasureCallback && mImpl->mActor.GetHandle())
167   {
168     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MeasureNode MeasureCallback executing on %s\n", mImpl->mActor.GetHandle().GetProperty<std::string>(Dali::Actor::Property::NAME).c_str());
169     mImpl->mMeasureCallback(mImpl->mActor.GetHandle(), width, widthMode, height, heightMode, &nodeSize);
170   }
171   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MeasureNode nodeSize width:%f height:%f\n", nodeSize.width, nodeSize.height);
172   return nodeSize;
173 }
174
175 void Node::CalculateLayout(float availableWidth, float availableHeight, bool isRTL)
176 {
177   DALI_LOG_INFO(gLogFilter, Debug::General, "CalculateLayout availableSize(%f,%f)\n", availableWidth, availableHeight);
178   YGNodeCalculateLayout(mImpl->mYogaNode, availableWidth, availableHeight, isRTL ? YGDirectionRTL : YGDirectionLTR);
179 }
180
181 Dali::Vector4 Node::GetNodeFrame(int index) const
182 {
183   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GetNodeFrame[%d]\n", index);
184   YGNodeRef     childNode = YGNodeGetChild(mImpl->mYogaNode, index);
185   Dali::Vector4 frame     = Vector4::ZERO;
186   if(childNode)
187   {
188     frame.x = YGNodeLayoutGetLeft(childNode);
189     frame.y = YGNodeLayoutGetTop(childNode);
190     frame.z = frame.x + YGNodeLayoutGetWidth(childNode);
191     frame.w = frame.y + YGNodeLayoutGetHeight(childNode);
192     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   }
194   else
195   {
196     frame.x = YGNodeLayoutGetLeft(mImpl->mYogaNode);
197     frame.y = YGNodeLayoutGetTop(mImpl->mYogaNode);
198     frame.z = frame.x + YGNodeLayoutGetWidth(mImpl->mYogaNode);
199     frame.w = frame.y + YGNodeLayoutGetHeight(mImpl->mYogaNode);
200     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);
201   }
202
203   return frame;
204 }
205 void Node::SetFlexDirection(Dali::Toolkit::Flex::FlexDirection flexDirection)
206 {
207   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex direction[%d]\n", flexDirection);
208
209   YGNodeStyleSetFlexDirection(mImpl->mYogaNode, static_cast<YGFlexDirection>(flexDirection));
210 }
211
212 Dali::Toolkit::Flex::FlexDirection Node::GetFlexDirection() const
213 {
214   return static_cast<Dali::Toolkit::Flex::FlexDirection>(YGNodeStyleGetFlexDirection(mImpl->mYogaNode));
215 }
216
217 void Node::SetFlexJustification(Dali::Toolkit::Flex::Justification flexJustification)
218 {
219   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex justification[%d]\n", flexJustification)
220
221   YGNodeStyleSetJustifyContent(mImpl->mYogaNode, static_cast<YGJustify>(flexJustification));
222 }
223
224 Dali::Toolkit::Flex::Justification Node::GetFlexJustification() const
225 {
226   return static_cast<Dali::Toolkit::Flex::Justification>(YGNodeStyleGetJustifyContent(mImpl->mYogaNode));
227 }
228
229 Dali::Toolkit::Flex::WrapType Node::GetFlexWrap() const
230 {
231   return static_cast<Dali::Toolkit::Flex::WrapType>(YGNodeStyleGetFlexWrap(mImpl->mYogaNode));
232 }
233
234 void Node::SetFlexAlignment(Dali::Toolkit::Flex::Alignment flexAlignment)
235 {
236   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex alignment[%d]\n", flexAlignment)
237
238   YGNodeStyleSetAlignContent(mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment));
239 }
240
241 Dali::Toolkit::Flex::Alignment Node::GetFlexAlignment() const
242 {
243   return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignContent(mImpl->mYogaNode));
244 }
245
246 void Node::SetFlexItemsAlignment(Dali::Toolkit::Flex::Alignment flexAlignment)
247 {
248   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex items alignment[%d] on mYogaNode[%p]\n", flexAlignment, mImpl->mYogaNode)
249
250   YGNodeStyleSetAlignItems(mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment));
251 }
252
253 Dali::Toolkit::Flex::Alignment Node::GetFlexItemsAlignment() const
254 {
255   return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignItems(mImpl->mYogaNode));
256 }
257
258 void Node::SetFlexAlignmentSelf(Dali::Toolkit::Flex::Alignment flexAlignmentSelf)
259 {
260   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex alignment self [%d] on mYogaNode[%p]\n", flexAlignmentSelf, mImpl->mYogaNode)
261
262   YGNodeStyleSetAlignSelf(mImpl->mYogaNode, static_cast<YGAlign>(flexAlignmentSelf));
263 }
264
265 Dali::Toolkit::Flex::Alignment Node::GetFlexAlignmentSelf() const
266 {
267   return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignSelf(mImpl->mYogaNode));
268 }
269
270 void Node::SetFlexPositionType(Dali::Toolkit::Flex::PositionType flexPositionType)
271 {
272   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex position type [%d] on mYogaNode[%p]\n", flexPositionType, mImpl->mYogaNode)
273
274   YGNodeStyleSetPositionType(mImpl->mYogaNode, static_cast<YGPositionType>(flexPositionType));
275 }
276
277 Dali::Toolkit::Flex::PositionType Node::GetFlexPositionType() const
278 {
279   return static_cast<Dali::Toolkit::Flex::PositionType>(YGNodeStyleGetPositionType(mImpl->mYogaNode));
280 }
281
282 void Node::SetFlexAspectRatio(float flexAspectRatio)
283 {
284   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex aspect ratio [%d] on mYogaNode[%p]\n", flexAspectRatio, mImpl->mYogaNode)
285
286   YGNodeStyleSetAspectRatio(mImpl->mYogaNode, static_cast<float>(flexAspectRatio));
287 }
288
289 float Node::GetFlexAspectRatio() const
290 {
291   return static_cast<float>(YGNodeStyleGetAspectRatio(mImpl->mYogaNode));
292 }
293
294 void Node::SetFlexBasis(float flexBasis)
295 {
296   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex basis [%d] on mYogaNode[%p]\n", flexBasis, mImpl->mYogaNode)
297
298   YGNodeStyleSetFlexBasis(mImpl->mYogaNode, static_cast<float>(flexBasis));
299 }
300
301 float Node::GetFlexBasis() const
302 {
303   return static_cast<float>(YGNodeStyleGetFlexBasis(mImpl->mYogaNode).value);
304 }
305
306 void Node::SetFlexShrink(float flexShrink)
307 {
308   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex shrink [%d] on mYogaNode[%p]\n", flexShrink, mImpl->mYogaNode)
309
310   YGNodeStyleSetFlexShrink(mImpl->mYogaNode, static_cast<float>(flexShrink));
311 }
312
313 float Node::GetFlexShrink() const
314 {
315   return static_cast<float>(YGNodeStyleGetFlexShrink(mImpl->mYogaNode));
316 }
317
318 void Node::SetFlexGrow(float flexGrow)
319 {
320   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex grow [%d] on mYogaNode[%p]\n", flexGrow, mImpl->mYogaNode)
321
322   YGNodeStyleSetFlexGrow(mImpl->mYogaNode, static_cast<float>(flexGrow));
323 }
324
325 float Node::GetFlexGrow() const
326 {
327   return static_cast<float>(YGNodeStyleGetFlexGrow(mImpl->mYogaNode));
328 }
329
330 float Node::GetFlexWidth() const
331 {
332   float flexWidth = YGNodeLayoutGetWidth(mImpl->mYogaNode);
333   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] width[%f]\n", mImpl->mYogaNode, flexWidth)
334
335   return flexWidth;
336 }
337
338 float Node::GetFlexHeight() const
339 {
340   float flexHeight = YGNodeLayoutGetHeight(mImpl->mYogaNode);
341   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] height[%f]\n", mImpl->mYogaNode, flexHeight)
342
343   return flexHeight;
344 }
345
346 void Node::SetMargin(Extents margin)
347 {
348   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex margin\n")
349
350   YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeLeft, margin.start);
351   YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeTop, margin.top);
352   YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeRight, margin.end);
353   YGNodeStyleSetMargin(mImpl->mYogaNode, YGEdgeBottom, margin.bottom);
354 }
355
356 void Node::SetPadding(Extents padding)
357 {
358   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set padding\n")
359
360   YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeLeft, padding.start);
361   YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeTop, padding.top);
362   YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeRight, padding.end);
363   YGNodeStyleSetPadding(mImpl->mYogaNode, YGEdgeBottom, padding.bottom);
364 }
365
366 void Node::SetFlexWrap(Dali::Toolkit::Flex::WrapType wrapType)
367 {
368   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Set flex wrap[%d] on mYogaNode[%p]\n", wrapType, mImpl->mYogaNode)
369
370   YGNodeStyleSetFlexWrap(mImpl->mYogaNode, static_cast<YGWrap>(wrapType));
371 }
372
373 } // namespace Flex
374 } // namespace Toolkit
375 } // namespace Dali