[AT-SPI] Require ControlAccessible for Control
[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::make_unique<DevelControl::ControlAccessible>(actor, Dali::Accessibility::Role::FILLER);
192   });
193 }
194
195 void Alignment::OnRelayout(const Vector2& size, RelayoutContainer& container)
196 {
197   // lay out the actors
198   Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
199   anchorPointAndParentOrigin.z       = 0.5f;
200   // anchorPoint.x is initialized to 0.0, which is HORIZONTAL_LEFT
201   if(Toolkit::Alignment::HORIZONTAL_CENTER == mHorizontal)
202   {
203     anchorPointAndParentOrigin.x = 0.5f;
204   }
205   else if(Toolkit::Alignment::HORIZONTAL_RIGHT == mHorizontal)
206   {
207     anchorPointAndParentOrigin.x = 1.0f;
208   }
209   // anchorPoint.y is initialized to 0.0, which is VERTICAL_TOP
210   if(Toolkit::Alignment::VERTICAL_CENTER == mVertical)
211   {
212     anchorPointAndParentOrigin.y = 0.5f;
213   }
214   else if(Toolkit::Alignment::VERTICAL_BOTTOM == mVertical)
215   {
216     anchorPointAndParentOrigin.y = 1.0f;
217   }
218
219   for(unsigned int i = 0, childCount = Self().GetChildCount(); i < childCount; ++i)
220   {
221     Actor child = Self().GetChildAt(i);
222
223     child.SetProperty(Actor::Property::ANCHOR_POINT, anchorPointAndParentOrigin);
224     child.SetProperty(Actor::Property::PARENT_ORIGIN, anchorPointAndParentOrigin);
225
226     Vector2 currentChildSize(child.GetTargetSize().GetVectorXY());
227     if(currentChildSize == Vector2::ZERO)
228     {
229       currentChildSize = child.GetNaturalSize();
230     }
231
232     bool    renegotiate = true;
233     Vector2 newChildSize;
234     newChildSize.width  = size.width - (mPadding.left + mPadding.right);
235     newChildSize.height = size.height - (mPadding.top + mPadding.bottom);
236
237     // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
238     if((newChildSize.width > Math::MACHINE_EPSILON_1000) && (newChildSize.height > Math::MACHINE_EPSILON_1000) &&
239        (currentChildSize.width > Math::MACHINE_EPSILON_1000) && (currentChildSize.height > Math::MACHINE_EPSILON_1000))
240     {
241       // no point trying to squeeze actors into too small size
242       switch(mScaling)
243       {
244         case Toolkit::Alignment::SCALE_NONE:
245         {
246           // Nothing to do
247           renegotiate = false;
248           break;
249         }
250         case Toolkit::Alignment::SCALE_TO_FILL:
251         {
252           // Nothing to do, newChildSize is already full size minus padding
253           break;
254         }
255         case Toolkit::Alignment::SCALE_TO_FIT_KEEP_ASPECT:
256         {
257           newChildSize = currentChildSize * std::min((newChildSize.width / currentChildSize.width), (newChildSize.height / currentChildSize.height));
258           break;
259         }
260         case Toolkit::Alignment::SCALE_TO_FILL_KEEP_ASPECT:
261         {
262           newChildSize = currentChildSize * std::max((newChildSize.width / currentChildSize.width), (newChildSize.height / currentChildSize.height));
263           break;
264         }
265         case Toolkit::Alignment::SHRINK_TO_FIT:
266         {
267           newChildSize = Vector2(std::min(newChildSize.width, currentChildSize.width), std::min(newChildSize.height, currentChildSize.height));
268           break;
269         }
270         case Toolkit::Alignment::SHRINK_TO_FIT_KEEP_ASPECT:
271         {
272           // check source size vs target size to see if we need to shrink
273           float widthScale  = (newChildSize.width < currentChildSize.width) ? (newChildSize.width / currentChildSize.width) : 1.f;
274           float heightScale = (newChildSize.height < currentChildSize.height) ? (newChildSize.height / currentChildSize.height) : 1.0f;
275           // use smaller of the scales
276           float scale = std::min(widthScale, heightScale);
277           // check if we need to scale
278           if(scale < 1.0f)
279           {
280             // scale natural size to fit inside
281             newChildSize *= scale;
282           }
283           break;
284         }
285       }
286     }
287
288     child.SetProperty(Actor::Property::POSITION, GetPosition(mPadding, mHorizontal, mVertical, newChildSize, currentChildSize));
289
290     if(renegotiate)
291     {
292       container.Add(child, newChildSize);
293     }
294   }
295 }
296
297 Alignment::Alignment(Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical)
298 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
299   mHorizontal(horizontal),
300   mVertical(vertical),
301   mScaling(Toolkit::Alignment::SCALE_NONE),
302   mPadding(0.f, 0.f, 0.f, 0.f)
303 {
304 }
305
306 Alignment::~Alignment()
307 {
308 }
309
310 } // namespace Internal
311
312 } // namespace Toolkit
313
314 } // namespace Dali