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