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