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