Merge "Include the algorithm header file" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-relayouter.cpp
1 /*
2  * Copyright (c) 2020 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/public-api/math/vector2.h>
23 #include <dali/public-api/math/vector3.h>
24 #include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
25
26 namespace Dali
27 {
28
29 namespace Internal
30 {
31
32 Actor::Relayouter::Relayouter()
33 : sizeModeFactor( DEFAULT_SIZE_MODE_FACTOR ),
34   preferredSize( DEFAULT_PREFERRED_SIZE ),
35   sizeSetPolicy( DEFAULT_SIZE_SCALE_POLICY ),
36   relayoutEnabled( false ),
37   insideRelayout( false )
38 {
39   // Set size negotiation defaults
40   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
41   {
42     resizePolicies[ i ] = ResizePolicy::DEFAULT;
43     useAssignedSize[ i ] = false;
44     negotiatedDimensions[ i ] = 0.0f;
45     dimensionNegotiated[ i ] = false;
46     dimensionDirty[ i ] = false;
47     dimensionDependencies[ i ] = Dimension::ALL_DIMENSIONS;
48     dimensionPadding[ i ] = DEFAULT_DIMENSION_PADDING;
49     minimumSize[ i ] = 0.0f;
50     maximumSize[ i ] = FLT_MAX;
51   }
52 }
53
54 ResizePolicy::Type Actor::Relayouter::GetResizePolicy( Dimension::Type dimension ) const
55 {
56   // If more than one dimension is requested, just return the first one found
57   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
58   {
59     if( ( dimension & ( 1 << i ) ) )
60     {
61       if( useAssignedSize[ i ] )
62       {
63         return ResizePolicy::USE_ASSIGNED_SIZE;
64       }
65       else
66       {
67         return resizePolicies[ i ];
68       }
69     }
70   }
71
72   return ResizePolicy::DEFAULT;
73 }
74
75 void Actor::Relayouter::SetPadding( const Vector2& padding, Dimension::Type dimension )
76 {
77   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
78   {
79     if( dimension & ( 1 << i ) )
80     {
81       dimensionPadding[ i ] = padding;
82     }
83   }
84 }
85
86 void Actor::Relayouter::SetLayoutNegotiated( bool negotiated, Dimension::Type dimension )
87 {
88   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
89   {
90     if( dimension & ( 1 << i ) )
91     {
92       dimensionNegotiated[ i ] = negotiated;
93     }
94   }
95 }
96
97 bool Actor::Relayouter::IsLayoutNegotiated( Dimension::Type dimension ) const
98 {
99   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
100   {
101     if( ( dimension & ( 1 << i ) ) && dimensionNegotiated[ i ] )
102     {
103       return true;
104     }
105   }
106   return false;
107 }
108
109 Vector2 Actor::Relayouter::ApplySizeSetPolicy( Internal::Actor& actor, const Vector2& size )
110 {
111   switch( sizeSetPolicy )
112   {
113     case SizeScalePolicy::USE_SIZE_SET:
114     {
115       return size;
116     }
117
118     case SizeScalePolicy::FIT_WITH_ASPECT_RATIO:
119     {
120       // Scale size to fit within the original size bounds, keeping the natural size aspect ratio
121       const Vector3 naturalSize = actor.GetNaturalSize();
122       if( naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f )
123       {
124         const float sizeRatio = size.width / size.height;
125         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
126
127         if( naturalSizeRatio < sizeRatio )
128         {
129           return Vector2( naturalSizeRatio * size.height, size.height );
130         }
131         else if( naturalSizeRatio > sizeRatio )
132         {
133           return Vector2( size.width, size.width / naturalSizeRatio );
134         }
135         else
136         {
137           return size;
138         }
139       }
140
141       break;
142     }
143
144     case SizeScalePolicy::FILL_WITH_ASPECT_RATIO:
145     {
146       // Scale size to fill the original size bounds, keeping the natural size aspect ratio. Potentially exceeding the original bounds.
147       const Vector3 naturalSize = actor.GetNaturalSize();
148       if( naturalSize.width > 0.0f && naturalSize.height > 0.0f && size.width > 0.0f && size.height > 0.0f )
149       {
150         const float sizeRatio = size.width / size.height;
151         const float naturalSizeRatio = naturalSize.width / naturalSize.height;
152
153         if( naturalSizeRatio < sizeRatio )
154         {
155           return Vector2( size.width, size.width / naturalSizeRatio );
156         }
157         else if( naturalSizeRatio > sizeRatio )
158         {
159           return Vector2( naturalSizeRatio * size.height, size.height );
160         }
161         else
162         {
163           return size;
164         }
165       }
166       break;
167     }
168
169     default:
170     {
171       break;
172     }
173   }
174
175   return size;
176 }
177
178 void Actor::Relayouter::SetUseAssignedSize( bool use, Dimension::Type dimension )
179 {
180   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
181   {
182     if( dimension & ( 1 << i ) )
183     {
184       useAssignedSize[ i ] = use;
185     }
186   }
187 }
188
189 bool Actor::Relayouter::GetUseAssignedSize( Dimension::Type dimension ) const
190 {
191   // If more than one dimension is requested, just return the first one found
192   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
193   {
194     if( dimension & ( 1 << i ) )
195     {
196       return useAssignedSize[ i ];
197     }
198   }
199
200   return false;
201 }
202
203 void Actor::Relayouter::SetMinimumSize( float size, Dimension::Type dimension )
204 {
205   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
206   {
207     if( dimension & ( 1 << i ) )
208     {
209       minimumSize[ i ] = size;
210     }
211   }
212 }
213
214 float Actor::Relayouter::GetMinimumSize( Dimension::Type dimension ) const
215 {
216   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
217   {
218     if( dimension & ( 1 << i ) )
219     {
220       return minimumSize[ i ];
221     }
222   }
223
224   return 0.0f;  // Default
225 }
226
227 void Actor::Relayouter::SetMaximumSize( float size, Dimension::Type dimension )
228 {
229   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
230   {
231     if( dimension & ( 1 << i ) )
232     {
233       maximumSize[ i ] = size;
234     }
235   }
236 }
237
238 float Actor::Relayouter::GetMaximumSize( Dimension::Type dimension ) const
239 {
240   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
241   {
242     if( dimension & ( 1 << i ) )
243     {
244       return maximumSize[ i ];
245     }
246   }
247
248   return FLT_MAX;  // Default
249 }
250
251 void Actor::Relayouter::SetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize )
252 {
253   ResizePolicy::Type originalWidthPolicy = GetResizePolicy(Dimension::WIDTH);
254   ResizePolicy::Type originalHeightPolicy = GetResizePolicy(Dimension::HEIGHT);
255
256   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
257   {
258     if( dimension & ( 1 << i ) )
259     {
260       if ( policy == ResizePolicy::USE_ASSIGNED_SIZE )
261       {
262         useAssignedSize[ i ] = true;
263       }
264       else
265       {
266         resizePolicies[ i ] = policy;
267         useAssignedSize[ i ] = false;
268       }
269     }
270   }
271
272   if( policy == ResizePolicy::DIMENSION_DEPENDENCY )
273   {
274     if( dimension & Dimension::WIDTH )
275     {
276       SetDimensionDependency( Dimension::WIDTH, Dimension::HEIGHT );
277     }
278
279     if( dimension & Dimension::HEIGHT )
280     {
281       SetDimensionDependency( Dimension::HEIGHT, Dimension::WIDTH );
282     }
283   }
284
285   // If calling SetResizePolicy, assume we want relayout enabled
286   relayoutEnabled = true;
287
288   // If the resize policy is set to be FIXED, the preferred size
289   // should be overrided by the target size. Otherwise the target
290   // size should be overrided by the preferred size.
291
292   if( dimension & Dimension::WIDTH )
293   {
294     if( originalWidthPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED )
295     {
296       preferredSize.width = targetSize.width;
297     }
298     else if( originalWidthPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED )
299     {
300       targetSize.width = preferredSize.width;
301     }
302   }
303
304   if( dimension & Dimension::HEIGHT )
305   {
306     if( originalHeightPolicy != ResizePolicy::FIXED && policy == ResizePolicy::FIXED )
307     {
308       preferredSize.height = targetSize.height;
309     }
310     else if( originalHeightPolicy == ResizePolicy::FIXED && policy != ResizePolicy::FIXED )
311     {
312       targetSize.height = preferredSize.height;
313     }
314   }
315 }
316
317 void Actor::Relayouter::SetDimensionDependency( Dimension::Type dimension, Dimension::Type dependency )
318 {
319   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
320   {
321     if( dimension & ( 1 << i ) )
322     {
323       dimensionDependencies[ i ] = dependency;
324     }
325   }
326 }
327
328 Dimension::Type Actor::Relayouter::GetDimensionDependency( Dimension::Type dimension ) const
329 {
330   // If more than one dimension is requested, just return the first one found
331   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
332   {
333     if( ( dimension & ( 1 << i ) ) )
334     {
335       return dimensionDependencies[ i ];
336     }
337   }
338
339   return Dimension::ALL_DIMENSIONS;   // Default
340 }
341
342 void Actor::Relayouter::SetLayoutDirty( bool dirty, Dimension::Type dimension )
343 {
344   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
345   {
346     if( dimension & ( 1 << i ) )
347     {
348       dimensionDirty[ i ] = dirty;
349     }
350   }
351 }
352
353 bool Actor::Relayouter::IsLayoutDirty( Dimension::Type dimension ) const
354 {
355   for( uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i )
356   {
357     if( ( dimension & ( 1 << i ) ) && dimensionDirty[ i ] )
358     {
359       return true;
360     }
361   }
362
363   return false;
364 }
365
366 float Actor::Relayouter::ClampDimension( const Internal::Actor& actor, float size, Dimension::Type dimension )
367 {
368   const float minSize = actor.GetMinimumSize( dimension );
369   const float maxSize = actor.GetMaximumSize( dimension );
370
371   return std::max( minSize, std::min( size, maxSize ) );
372 }
373
374 } // namespace Internal
375
376 } // namespace Dali