9a486ed59671b3f267e9736587ace43448b6411c
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / view / view-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 "view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/constraints.h>
23 #include <dali/public-api/common/stage.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/object/type-registry-helper.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38
39 BaseHandle Create()
40 {
41   return Toolkit::View::New();
42 }
43
44 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::View, Toolkit::Control, Create )
45
46 DALI_SIGNAL_REGISTRATION( View, "orientation-animation-start", SIGNAL_ORIENTATION_ANIMATION_START )
47
48 DALI_TYPE_REGISTRATION_END()
49
50 const float ROTATION_ANIMATION_DURATION = 0.5f;
51
52 }
53
54 Toolkit::View View::New( bool fullscreen )
55 {
56   // Create the implementation, temporarily owned by this handle on stack
57   IntrusivePtr< View > internalView = new View(fullscreen);
58
59   // Pass ownership to CustomActor handle
60   Toolkit::View view( *internalView );
61
62   // Second-phase init of the implementation
63   // This can only be done after the CustomActor connection has been made...
64   internalView->Initialize();
65
66   return view;
67 }
68
69 Layer View::GetContentLayer( unsigned int index ) const
70 {
71   // Returns the layer stored in the layer map.
72   Layer layer;
73
74   LayerConstIt it = mContentLayers.find( index );
75
76   if( it != mContentLayers.end() )
77   {
78     layer = it->second;
79   }
80
81   return layer;
82 }
83
84 unsigned int View::AddContentLayer( Layer layer )
85 {
86   // layer must exist.
87   DALI_ASSERT_ALWAYS( layer );
88
89   unsigned int index = mNextLayerIndex;
90   LayerIt it = FindLayer( layer );
91
92   if( it == mContentLayers.end() )
93   {
94     // Add layer to the custom actor.
95     Self().Add( layer );
96
97     // Store the layer.
98     mContentLayers[mNextLayerIndex] = layer;
99
100     // Increase the index.
101     ++mNextLayerIndex;
102   }
103
104   return index;
105 }
106
107 void View::RemoveContentLayer( Layer layer )
108 {
109   // Check if layer was added in this view.
110   LayerIt it = FindLayer( layer );
111   if( it != mContentLayers.end() )
112   {
113     // Remove layer from custom actor.
114     Self().Remove( layer );
115
116     // Remove layer from layer map.
117     mContentLayers.erase( it );
118   }
119 }
120
121 Layer View::GetBackgroundLayer() const
122 {
123   return mBackgroundLayer;
124 }
125
126 void View::SetBackground( ImageActor backgroundImage )
127 {
128   // Create background layer if doesn't exist.
129
130   if( !mBackgroundLayer )
131   {
132     mBackgroundLayer = Layer::New();
133
134     mBackgroundLayer.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
135     mBackgroundLayer.SetSize( mViewSize );
136
137     // Add background layer to custom actor.
138     Self().Add( mBackgroundLayer );
139
140     // Drop the background layer
141
142     DALI_ASSERT_ALWAYS( mBackgroundLayer.OnStage() ); // We need to be on-stage to drop the layer
143     mBackgroundLayer.LowerToBottom();
144   }
145   else
146   {
147     // It removes the old background
148     if( 0 < mBackgroundLayer.GetChildCount() )
149     {
150       mBackgroundLayer.Remove( mBackgroundLayer.GetChildAt(0) );
151     }
152   }
153
154   backgroundImage.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
155   backgroundImage.SetScale( FillXYKeepAspectRatio( mViewSize, backgroundImage.GetSize() ) );
156   mBackgroundLayer.Add( backgroundImage );
157 }
158
159 void View::SetOrientationFunction( Degree portrait, Degree landscale, Degree portraitInverse, Degree landscapeInverse )
160 {
161   mOrientationFunction[View::PORTRAIT] = portrait;
162   mOrientationFunction[View::LANDSCAPE] = landscale;
163   mOrientationFunction[View::PORTRAIT_INVERSE] = portraitInverse;
164   mOrientationFunction[View::LANDSCAPE_INVERSE] = landscapeInverse;
165 }
166
167 void View::OrientationChanged( Dali::Orientation orientation )
168 {
169   // Nothing to do if orientation doesn't really change.
170   if ( orientation.GetDegrees() == mOrientation || !mAutoRotateEnabled )
171   {
172     return;
173   }
174
175   mOrientation = orientation.GetDegrees();
176
177   // has parent so we expect it to be on stage
178   mRotateAnimation = Animation::New( ROTATION_ANIMATION_DURATION );
179   mRotateAnimation.RotateTo( Self(), Degree( -orientation.GetDegrees() ), Vector3::ZAXIS, AlphaFunctions::EaseOut );
180
181   // Resize the view
182   if( mFullScreen )
183   {
184     const Vector2& stageSize( Stage::GetCurrent().GetSize() );
185     const Vector3& currentSize( Self().GetCurrentSize() );
186
187     float minSize = std::min( stageSize.width, stageSize.height );
188     float maxSize = std::max( stageSize.width, stageSize.height );
189
190     Vector3 targetSize;
191     View::Orientation viewOrientation = DegreeToViewOrientation( Degree( orientation.GetDegrees() ) );
192     switch( viewOrientation )
193     {
194       case View::PORTRAIT:          // Fallthrough
195       case View::PORTRAIT_INVERSE:
196         targetSize = Vector3( minSize, maxSize, currentSize.depth );
197         break;
198       case View::LANDSCAPE:         // Fallthrough
199       case View::LANDSCAPE_INVERSE:
200         targetSize = Vector3( maxSize, minSize, currentSize.depth );
201         break;
202       default:
203         DALI_ASSERT_ALWAYS( false );
204     }
205
206     // if we linearly resize from portrait to landscape halfway through the animation
207     // we get size which is square between the both. This would cause a square image to grow
208     // if it is fitted to be 100% of view size. Therefore we do a nonlinear size animation
209     // where we shrink faster
210     // which one grows
211     if( targetSize.width > currentSize.width )
212     {
213       // width grows, shrink height faster
214       Vector3 shrink( currentSize );shrink.height = targetSize.height;
215       mRotateAnimation.Resize( Self(), shrink, AlphaFunctions::EaseOut, 0.0f, ROTATION_ANIMATION_DURATION * 0.5f );
216       mRotateAnimation.Resize( Self(), targetSize, AlphaFunctions::EaseIn, 0.0f, ROTATION_ANIMATION_DURATION );
217     }
218     else
219     {
220       // height grows, shrink width faster
221       Vector3 shrink( currentSize );shrink.width = targetSize.width;
222       mRotateAnimation.Resize( Self(), shrink, AlphaFunctions::EaseOut, 0.0f, ROTATION_ANIMATION_DURATION * 0.5f );
223       mRotateAnimation.Resize( Self(), targetSize, AlphaFunctions::EaseIn, 0.0f, ROTATION_ANIMATION_DURATION );
224     }
225   }
226
227   Toolkit::View handle( GetOwner() );
228   mOrientationAnimationStartedSignal.Emit( handle, mRotateAnimation, orientation );
229
230   mRotateAnimation.Play();
231 }
232
233 void View::SetAutoRotate( bool enabled )
234 {
235   mAutoRotateEnabled = enabled;
236 }
237
238 Toolkit::View::OrientationAnimationStartedSignalType& View::OrientationAnimationStartedSignal()
239 {
240   return mOrientationAnimationStartedSignal;
241 }
242
243 bool View::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
244 {
245   Dali::BaseHandle handle( object );
246
247   bool connected( true );
248   Toolkit::View view = Toolkit::View::DownCast(handle);
249
250   if( 0 == strcmp( signalName.c_str(), SIGNAL_ORIENTATION_ANIMATION_START ) )
251   {
252     view.OrientationAnimationStartedSignal().Connect( tracker, functor );
253   }
254   else
255   {
256     // signalName does not match any signal
257     connected = false;
258   }
259
260   return connected;
261 }
262
263 View::View(bool fullscreen)
264 : Control( CONTROL_BEHAVIOUR_NONE ),
265   mOrientation( -1 ),
266   mFullScreen(fullscreen),
267   mContentLayers(),
268   mNextLayerIndex( 0 ),
269   mOrientationFunction(),
270   mAutoRotateEnabled( true )
271 {
272   mOrientationFunction[View::PORTRAIT] = 0.f;
273   mOrientationFunction[View::LANDSCAPE] = 90.f;
274   mOrientationFunction[View::PORTRAIT_INVERSE] = 180.f;
275   mOrientationFunction[View::LANDSCAPE_INVERSE] =  270.f;
276 }
277
278 View::~View()
279 {
280 }
281
282 void View::OnInitialize()
283 {
284   Self().SetAnchorPoint( AnchorPoint::CENTER );
285   Self().SetParentOrigin( ParentOrigin::CENTER );
286
287   if( mFullScreen )
288   {
289     Self().SetSize( Stage::GetCurrent().GetSize() );
290   }
291 }
292
293 void View::OnControlSizeSet( const Vector3& targetSize )
294 {
295   mViewSize = targetSize;
296   if( mBackgroundLayer )
297   {
298     mBackgroundLayer.SetSize( mViewSize );
299     if( mBackgroundLayer.GetChildCount() > 0 )
300     {
301       Actor background = mBackgroundLayer.GetChildAt(0);
302       background.SetScale( FillXYKeepAspectRatio( mViewSize, background.GetSize() ) );
303     }
304   }
305 }
306
307 View::Orientation View::DegreeToViewOrientation( Degree degree )
308 {
309   View::Orientation orientation = PORTRAIT;
310
311   if( fabsf( mOrientationFunction[PORTRAIT] - degree ) <= GetRangedEpsilon( mOrientationFunction[PORTRAIT], degree ) )
312   {
313     orientation =  PORTRAIT;
314   }
315   else if( fabsf( mOrientationFunction[LANDSCAPE] - degree ) <= GetRangedEpsilon( mOrientationFunction[LANDSCAPE], degree ) )
316   {
317     orientation = LANDSCAPE;
318   }
319   else if( fabsf( mOrientationFunction[PORTRAIT_INVERSE] - degree ) <= GetRangedEpsilon( mOrientationFunction[PORTRAIT_INVERSE], degree ) )
320   {
321     orientation = PORTRAIT_INVERSE;
322   }
323   else if( fabsf( mOrientationFunction[LANDSCAPE_INVERSE] - degree ) <= GetRangedEpsilon( mOrientationFunction[LANDSCAPE_INVERSE], degree ) )
324   {
325     orientation = LANDSCAPE_INVERSE;
326   }
327
328   return orientation;
329 }
330
331 View::LayerIt View::FindLayer( Layer layer )
332 {
333   for( LayerIt it = mContentLayers.begin(); it != mContentLayers.end(); ++it )
334   {
335     if(layer == it->second)
336     {
337       return it;
338     }
339   }
340
341   return mContentLayers.end();
342 }
343
344 } // namespace Internal
345
346 } // namespace Toolkit
347
348 } // namespace Dali