cfebf864e53db63a89a888953315d7141975ecdb
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-relayouter.cpp
1 /*
2  * Copyright (c) 2021 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
18 // CLASS HEADER
19 #include <dali/internal/event/actors/actor-relayouter.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/actors/actor.h>
24 #include <dali/public-api/math/vector2.h>
25 #include <dali/public-api/math/vector3.h>
26
27 #include <dali/internal/event/actors/actor-impl.h>
28 #include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
29
30 #if defined(DEBUG_ENABLED)
31 Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER");
32 #endif
33
34 namespace Dali
35 {
36 namespace Internal
37 {
38 ActorSizer::Relayouter::Relayouter()
39 : sizeModeFactor(DEFAULT_SIZE_MODE_FACTOR),
40   preferredSize(DEFAULT_PREFERRED_SIZE),
41   sizeSetPolicy(DEFAULT_SIZE_SCALE_POLICY),
42   relayoutEnabled(false),
43   insideRelayout(false),
44   relayoutRequested(false)
45 {
46   // Set size negotiation defaults
47   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
48   {
49     resizePolicies[i]        = ResizePolicy::DEFAULT;
50     useAssignedSize[i]       = false;
51     negotiatedDimensions[i]  = 0.0f;
52     dimensionNegotiated[i]   = false;
53     dimensionDirty[i]        = false;
54     dimensionDependencies[i] = Dimension::ALL_DIMENSIONS;
55     dimensionPadding[i]      = DEFAULT_DIMENSION_PADDING;
56     minimumSize[i]           = 0.0f;
57     maximumSize[i]           = FLT_MAX;
58   }
59 }
60
61 ResizePolicy::Type ActorSizer::Relayouter::GetResizePolicy(Dimension::Type dimension) const
62 {
63   // If more than one dimension is requested, just return the first one found
64   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
65   {
66     if((dimension & (1 << i)))
67     {
68       if(useAssignedSize[i])
69       {
70         return ResizePolicy::USE_ASSIGNED_SIZE;
71       }
72       else
73       {
74         return resizePolicies[i];
75       }
76     }
77   }
78
79   return ResizePolicy::DEFAULT;
80 }
81
82 Vector2 ActorSizer::Relayouter::ApplySizeSetPolicy(Internal::Actor& actor, const Vector2& size)
83 {
84   switch(sizeSetPolicy)
85   {
86     case SizeScalePolicy::USE_SIZE_SET:
87     {
88       return size;
89     }
90
91     case SizeScalePolicy::FIT_WITH_ASPECT_RATIO:
92     {
93       // Scale size to fit within the original size bounds, keeping the natural size aspect ratio
94       const Vector3 naturalSize = actor.GetNaturalSize();
95       if(naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f)
96       {
97         const float sizeRatio        = size.width / size.height;
98         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
99
100         if(naturalSizeRatio < sizeRatio)
101         {
102           return Vector2(naturalSizeRatio * size.height, size.height);
103         }
104         else if(naturalSizeRatio > sizeRatio)
105         {
106           return Vector2(size.width, size.width / naturalSizeRatio);
107         }
108         else
109         {
110           return size;
111         }
112       }
113
114       break;
115     }
116
117     case SizeScalePolicy::FILL_WITH_ASPECT_RATIO:
118     {
119       // Scale size to fill the original size bounds, keeping the natural size aspect ratio. Potentially exceeding the original bounds.
120       const Vector3 naturalSize = actor.GetNaturalSize();
121       if(naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f)
122       {
123         const float sizeRatio        = size.width / size.height;
124         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
125
126         if(naturalSizeRatio < sizeRatio)
127         {
128           return Vector2(size.width, size.width / naturalSizeRatio);
129         }
130         else if(naturalSizeRatio > sizeRatio)
131         {
132           return Vector2(naturalSizeRatio * size.height, size.height);
133         }
134         else
135         {
136           return size;
137         }
138       }
139       break;
140     }
141
142     default:
143     {
144       break;
145     }
146   }
147
148   return size;
149 }
150
151 void ActorSizer::Relayouter::SetUseAssignedSize(bool use, Dimension::Type dimension)
152 {
153   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
154   {
155     if(dimension & (1 << i))
156     {
157       useAssignedSize[i] = use;
158     }
159   }
160 }
161
162 bool ActorSizer::Relayouter::GetUseAssignedSize(Dimension::Type dimension) const
163 {
164   // If more than one dimension is requested, just return the first one found
165   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
166   {
167     if(dimension & (1 << i))
168     {
169       return useAssignedSize[i];
170     }
171   }
172
173   return false;
174 }
175
176 void ActorSizer::Relayouter::SetMinimumSize(float size, Dimension::Type dimension)
177 {
178   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
179   {
180     if(dimension & (1 << i))
181     {
182       minimumSize[i] = size;
183     }
184   }
185 }
186
187 float ActorSizer::Relayouter::GetMinimumSize(Dimension::Type dimension) const
188 {
189   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
190   {
191     if(dimension & (1 << i))
192     {
193       return minimumSize[i];
194     }
195   }
196
197   return 0.0f; // Default
198 }
199
200 void ActorSizer::Relayouter::SetMaximumSize(float size, Dimension::Type dimension)
201 {
202   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
203   {
204     if(dimension & (1 << i))
205     {
206       maximumSize[i] = size;
207     }
208   }
209 }
210
211 float ActorSizer::Relayouter::GetMaximumSize(Dimension::Type dimension) const
212 {
213   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
214   {
215     if(dimension & (1 << i))
216     {
217       return maximumSize[i];
218     }
219   }
220
221   return FLT_MAX; // Default
222 }
223
224 void ActorSizer::Relayouter::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize)
225 {
226   ResizePolicy::Type originalWidthPolicy  = GetResizePolicy(Dimension::WIDTH);
227   ResizePolicy::Type originalHeightPolicy = GetResizePolicy(Dimension::HEIGHT);
228
229   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
230   {
231     if(dimension & (1 << i))
232     {
233       if(policy == ResizePolicy::USE_ASSIGNED_SIZE)
234       {
235         useAssignedSize[i] = true;
236       }
237       else
238       {
239         resizePolicies[i]  = policy;
240         useAssignedSize[i] = false;
241       }
242     }
243   }
244
245   if(policy == ResizePolicy::DIMENSION_DEPENDENCY)
246   {
247     if(dimension & Dimension::WIDTH)
248     {
249       SetDimensionDependency(Dimension::WIDTH, Dimension::HEIGHT);
250     }
251
252     if(dimension & Dimension::HEIGHT)
253     {
254       SetDimensionDependency(Dimension::HEIGHT, Dimension::WIDTH);
255     }
256   }
257
258   // If calling SetResizePolicy, assume we want relayout enabled
259   relayoutEnabled = true;
260
261   // If the resize policy is set to be FIXED, the preferred size
262   // should be overrided by the target size. Otherwise the target
263   // size should be overrided by the preferred size.
264
265   if(dimension & Dimension::WIDTH)
266   {
267     if(originalWidthPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED)
268     {
269       preferredSize.width = targetSize.width;
270     }
271     else if(originalWidthPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED)
272     {
273       targetSize.width = preferredSize.width;
274     }
275   }
276
277   if(dimension & Dimension::HEIGHT)
278   {
279     if(originalHeightPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED)
280     {
281       preferredSize.height = targetSize.height;
282     }
283     else if(originalHeightPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED)
284     {
285       targetSize.height = preferredSize.height;
286     }
287   }
288 }
289
290 bool ActorSizer::Relayouter::GetRelayoutDependentOnParent(Dimension::Type dimension)
291 {
292   // Check if actor is dependent on parent
293   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
294   {
295     if((dimension & (1 << i)))
296     {
297       const ResizePolicy::Type resizePolicy = GetResizePolicy(static_cast<Dimension::Type>(1 << i));
298       if(resizePolicy == ResizePolicy::FILL_TO_PARENT || resizePolicy == ResizePolicy::SIZE_RELATIVE_TO_PARENT || resizePolicy == ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT)
299       {
300         return true;
301       }
302     }
303   }
304   return false;
305 }
306
307 bool ActorSizer::Relayouter::GetRelayoutDependentOnChildren(Dimension::Type dimension)
308 {
309   // Check if actor is dependent on children
310   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
311   {
312     if((dimension & (1 << i)))
313     {
314       const ResizePolicy::Type resizePolicy = GetResizePolicy(static_cast<Dimension::Type>(1 << i));
315       if(resizePolicy == ResizePolicy::FIT_TO_CHILDREN || resizePolicy == ResizePolicy::USE_NATURAL_SIZE)
316       {
317         return true;
318       }
319       break;
320     }
321   }
322
323   return false;
324 }
325
326 bool ActorSizer::Relayouter::GetRelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependency)
327 {
328   // Check each possible dimension and see if it is dependent on the input one
329   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
330   {
331     if(dimension & (1 << i))
332     {
333       return resizePolicies[i] == ResizePolicy::DIMENSION_DEPENDENCY && dimensionDependencies[i] == dependency;
334     }
335   }
336
337   return false;
338 }
339
340 void ActorSizer::Relayouter::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency)
341 {
342   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
343   {
344     if(dimension & (1 << i))
345     {
346       dimensionDependencies[i] = dependency;
347     }
348   }
349 }
350
351 Dimension::Type ActorSizer::Relayouter::GetDimensionDependency(Dimension::Type dimension) const
352 {
353   // If more than one dimension is requested, just return the first one found
354   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
355   {
356     if((dimension & (1 << i)))
357     {
358       return dimensionDependencies[i];
359     }
360   }
361
362   return Dimension::ALL_DIMENSIONS; // Default
363 }
364
365 void ActorSizer::Relayouter::SetLayoutDirty(bool dirty, Dimension::Type dimension)
366 {
367   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
368   {
369     if(dimension & (1 << i))
370     {
371       dimensionDirty[i] = dirty;
372     }
373   }
374 }
375
376 bool ActorSizer::Relayouter::IsLayoutDirty(Dimension::Type dimension) const
377 {
378   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
379   {
380     if((dimension & (1 << i)) && dimensionDirty[i])
381     {
382       return true;
383     }
384   }
385
386   return false;
387 }
388
389 void ActorSizer::Relayouter::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension)
390 {
391   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
392   {
393     if(dimension & (1 << i))
394     {
395       negotiatedDimensions[i] = negotiatedDimension;
396     }
397   }
398 }
399
400 float ActorSizer::Relayouter::GetNegotiatedDimension(Dimension::Type dimension)
401 {
402   // If more than one dimension is requested, just return the first one found
403   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
404   {
405     if((dimension & (1 << i)))
406     {
407       return negotiatedDimensions[i];
408     }
409   }
410
411   return 0.0f; // Default
412 }
413
414 void ActorSizer::Relayouter::SetPadding(const Vector2& padding, Dimension::Type dimension)
415 {
416   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
417   {
418     if(dimension & (1 << i))
419     {
420       dimensionPadding[i] = padding;
421     }
422   }
423 }
424
425 Vector2 ActorSizer::Relayouter::GetPadding(Dimension::Type dimension)
426 {
427   // If more than one dimension is requested, just return the first one found
428   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
429   {
430     if((dimension & (1 << i)))
431     {
432       return dimensionPadding[i];
433     }
434   }
435
436   return DEFAULT_DIMENSION_PADDING;
437 }
438
439 void ActorSizer::Relayouter::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension)
440 {
441   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
442   {
443     if(dimension & (1 << i))
444     {
445       dimensionNegotiated[i] = negotiated;
446     }
447   }
448 }
449
450 bool ActorSizer::Relayouter::IsLayoutNegotiated(Dimension::Type dimension) const
451 {
452   for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
453   {
454     if((dimension & (1 << i)) && dimensionNegotiated[i])
455     {
456       return true;
457     }
458   }
459   return false;
460 }
461
462 } // namespace Internal
463
464 } // namespace Dali