Merge "Use broken image when animated image loading is failed." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / alignment / alignment-impl.cpp
1 /*
2  * Copyright (c) 2014 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 "alignment-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/property-input.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/size-negotiation/relayout-container.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/controls/control-devel.h>
29
30 namespace Dali
31 {
32 namespace Toolkit
33 {
34 namespace Internal
35 {
36 namespace
37 {
38 //Type Registration
39 BaseHandle Create()
40 {
41   return Toolkit::Alignment::New();
42 }
43
44 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Alignment, Toolkit::Control, Create)
45 DALI_TYPE_REGISTRATION_END()
46
47 /**
48  * @param padding The padding value
49  * @param horizontalAlignment The horizontal alignment.
50  * @param verticalAlignment The vertical alignment.
51  * @param currentSize of the object
52  * @param parentSize
53  */
54 inline Vector3 GetPosition(const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment, const Vector2& currentSize, const Vector2& parentSize)
55 {
56   Vector3 position(0.f, 0.f, 0.f);
57
58   switch(horizontalAlignment)
59   {
60     case Dali::Toolkit::Alignment::HORIZONTAL_LEFT:
61     {
62       position.x += padding.left;
63       break;
64     }
65     case Dali::Toolkit::Alignment::HORIZONTAL_RIGHT:
66     {
67       position.x -= padding.right;
68       break;
69     }
70     case Dali::Toolkit::Alignment::HORIZONTAL_CENTER: // FALLTHROUGH
71     default:                                          // use center as default
72     {
73       if(currentSize.width + padding.left + padding.right >= parentSize.width)
74       {
75         position.x += 0.5f * (padding.left - padding.right);
76       }
77       break;
78     }
79   }
80
81   switch(verticalAlignment)
82   {
83     case Dali::Toolkit::Alignment::VERTICAL_TOP:
84     {
85       position.y += padding.top;
86       break;
87     }
88     case Dali::Toolkit::Alignment::VERTICAL_BOTTOM:
89     {
90       position.y -= padding.bottom;
91       break;
92     }
93     case Dali::Toolkit::Alignment::VERTICAL_CENTER: // FALLTHROUGH
94     default:                                        // use center as default
95     {
96       if(currentSize.height + padding.top + padding.bottom >= parentSize.height)
97       {
98         position.y += 0.5f * (padding.top - padding.bottom);
99       }
100       break;
101     }
102   }
103
104   return position;
105 }
106
107 } // namespace
108
109 Toolkit::Alignment Alignment::New(Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical)
110 {
111   // Create the implementation, temporarily owned on stack
112   IntrusivePtr<Alignment> internalAlignment = new Alignment(horizontal, vertical);
113
114   // Pass ownership to Toolkit::Alignment
115   Toolkit::Alignment alignment(*internalAlignment);
116
117   // Second-phase init of the implementation
118   // This can only be done after the CustomActor connection has been made...
119   internalAlignment->Initialize();
120
121   return alignment;
122 }
123
124 void Alignment::SetAlignmentType(Toolkit::Alignment::Type type)
125 {
126   // Horizontal Alignment
127   if(type & Toolkit::Alignment::HORIZONTAL_RIGHT)
128   {
129     mHorizontal = Toolkit::Alignment::HORIZONTAL_RIGHT;
130   }
131   if(type & Toolkit::Alignment::HORIZONTAL_LEFT)
132   {
133     mHorizontal = Toolkit::Alignment::HORIZONTAL_LEFT;
134   }
135   if(type & Toolkit::Alignment::HORIZONTAL_CENTER)
136   {
137     mHorizontal = Toolkit::Alignment::HORIZONTAL_CENTER;
138   }
139
140   // Vertical Alignment
141   if(type & Toolkit::Alignment::VERTICAL_BOTTOM)
142   {
143     mVertical = Toolkit::Alignment::VERTICAL_BOTTOM;
144   }
145   if(type & Toolkit::Alignment::VERTICAL_TOP)
146   {
147     mVertical = Toolkit::Alignment::VERTICAL_TOP;
148   }
149   if(type & Toolkit::Alignment::VERTICAL_CENTER)
150   {
151     mVertical = Toolkit::Alignment::VERTICAL_CENTER;
152   }
153
154   RelayoutRequest();
155 }
156
157 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
158 {
159   return Toolkit::Alignment::Type(mHorizontal | mVertical);
160 }
161
162 void Alignment::SetScaling(Toolkit::Alignment::Scaling scaling)
163 {
164   mScaling = scaling;
165
166   RelayoutRequest();
167 }
168
169 Toolkit::Alignment::Scaling Alignment::GetScaling() const
170 {
171   return mScaling;
172 }
173
174 void Alignment::SetPadding(const Toolkit::Alignment::Padding& padding)
175 {
176   DALI_ASSERT_ALWAYS((padding.left >= 0.f) && (padding.top >= 0.f) && (padding.right >= 0.f) && (padding.bottom >= 0.f));
177
178   mPadding = padding;
179
180   RelayoutRequest();
181 }
182
183 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
184 {
185   return mPadding;
186 }
187
188 void Alignment::OnInitialize()
189 {
190   DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
191     return std::unique_ptr<Dali::Accessibility::Accessible>(
192       new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::FILLER));
193   });
194 }
195
196 void Alignment::OnRelayout(const Vector2& size, RelayoutContainer& container)
197 {
198   // lay out the actors
199   Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
200   anchorPointAndParentOrigin.z       = 0.5f;
201   // anchorPoint.x is initialized to 0.0, which is HORIZONTAL_LEFT
202   if(Toolkit::Alignment::HORIZONTAL_CENTER == mHorizontal)
203   {
204     anchorPointAndParentOrigin.x = 0.5f;
205   }
206   else if(Toolkit::Alignment::HORIZONTAL_RIGHT == mHorizontal)
207   {
208     anchorPointAndParentOrigin.x = 1.0f;
209   }
210   // anchorPoint.y is initialized to 0.0, which is VERTICAL_TOP
211   if(Toolkit::Alignment::VERTICAL_CENTER == mVertical)
212   {
213     anchorPointAndParentOrigin.y = 0.5f;
214   }
215   else if(Toolkit::Alignment::VERTICAL_BOTTOM == mVertical)
216   {
217     anchorPointAndParentOrigin.y = 1.0f;
218   }
219
220   for(unsigned int i = 0, childCount = Self().GetChildCount(); i < childCount; ++i)
221   {
222     Actor child = Self().GetChildAt(i);
223
224     child.SetProperty(Actor::Property::ANCHOR_POINT, anchorPointAndParentOrigin);
225     child.SetProperty(Actor::Property::PARENT_ORIGIN, anchorPointAndParentOrigin);
226
227     Vector2 currentChildSize(child.GetTargetSize().GetVectorXY());
228     if(currentChildSize == Vector2::ZERO)
229     {
230       currentChildSize = child.GetNaturalSize();
231     }
232
233     bool    renegotiate = true;
234     Vector2 newChildSize;
235     newChildSize.width  = size.width - (mPadding.left + mPadding.right);
236     newChildSize.height = size.height - (mPadding.top + mPadding.bottom);
237
238     // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
239     if((newChildSize.width > Math::MACHINE_EPSILON_1000) && (newChildSize.height > Math::MACHINE_EPSILON_1000) &&
240        (currentChildSize.width > Math::MACHINE_EPSILON_1000) && (currentChildSize.height > Math::MACHINE_EPSILON_1000))
241     {
242       // no point trying to squeeze actors into too small size
243       switch(mScaling)
244       {
245         case Toolkit::Alignment::SCALE_NONE:
246         {
247           // Nothing to do
248           renegotiate = false;
249           break;
250         }
251         case Toolkit::Alignment::SCALE_TO_FILL:
252         {
253           // Nothing to do, newChildSize is already full size minus padding
254           break;
255         }
256         case Toolkit::Alignment::SCALE_TO_FIT_KEEP_ASPECT:
257         {
258           newChildSize = currentChildSize * std::min((newChildSize.width / currentChildSize.width), (newChildSize.height / currentChildSize.height));
259           break;
260         }
261         case Toolkit::Alignment::SCALE_TO_FILL_KEEP_ASPECT:
262         {
263           newChildSize = currentChildSize * std::max((newChildSize.width / currentChildSize.width), (newChildSize.height / currentChildSize.height));
264           break;
265         }
266         case Toolkit::Alignment::SHRINK_TO_FIT:
267         {
268           newChildSize = Vector2(std::min(newChildSize.width, currentChildSize.width), std::min(newChildSize.height, currentChildSize.height));
269           break;
270         }
271         case Toolkit::Alignment::SHRINK_TO_FIT_KEEP_ASPECT:
272         {
273           // check source size vs target size to see if we need to shrink
274           float widthScale  = (newChildSize.width < currentChildSize.width) ? (newChildSize.width / currentChildSize.width) : 1.f;
275           float heightScale = (newChildSize.height < currentChildSize.height) ? (newChildSize.height / currentChildSize.height) : 1.0f;
276           // use smaller of the scales
277           float scale = std::min(widthScale, heightScale);
278           // check if we need to scale
279           if(scale < 1.0f)
280           {
281             // scale natural size to fit inside
282             newChildSize *= scale;
283           }
284           break;
285         }
286       }
287     }
288
289     child.SetProperty(Actor::Property::POSITION, GetPosition(mPadding, mHorizontal, mVertical, newChildSize, currentChildSize));
290
291     if(renegotiate)
292     {
293       container.Add(child, newChildSize);
294     }
295   }
296 }
297
298 Alignment::Alignment(Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical)
299 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
300   mHorizontal(horizontal),
301   mVertical(vertical),
302   mScaling(Toolkit::Alignment::SCALE_NONE),
303   mPadding(0.f, 0.f, 0.f, 0.f)
304 {
305 }
306
307 Alignment::~Alignment()
308 {
309 }
310
311 } // namespace Internal
312
313 } // namespace Toolkit
314
315 } // namespace Dali