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