Remove non-public APIs of Animation
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / navigation-frame / navigation-control-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 "navigation-control-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/animation.h>
23 #include <dali/public-api/events/key-event.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/object/type-registry-helper.h>
26 #include <dali/public-api/size-negotiation/relayout-container.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/public-api/focus-manager/focus-manager.h>
30 #include <dali-toolkit/internal/controls/navigation-frame/navigation-tool-bar.h>
31 #include <dali-toolkit/internal/controls/navigation-frame/navigation-title-bar.h>
32 #include <dali-toolkit/public-api/focus-manager/focus-manager.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Internal
41 {
42
43 namespace // to register type
44 {
45
46 BaseHandle Create()
47 {
48   return Toolkit::NavigationControl::New();
49 }
50
51 // Setup properties, signals and actions using the type-registry.
52 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::NavigationControl, Toolkit::Control, Create )
53
54 DALI_ACTION_REGISTRATION( NavigationControl, "push", ACTION_PUSH )
55 DALI_ACTION_REGISTRATION( NavigationControl, "pop",  ACTION_POP  )
56
57 DALI_TYPE_REGISTRATION_END()
58
59 }
60
61 NavigationControl::NavigationControl()
62 : Control( REQUIRES_TOUCH_EVENTS ),
63   mToolBar(NULL),
64   mTitleBar(NULL),
65   mOrientationAngle( 0 ),
66   mOrientationAnimationDuration( 1.0f ),
67   mOrientationAnimationAlphaFunc( AlphaFunctions::EaseOut ),
68   mItemPositionCoefficient( Vector3( 0.0f, 1.0f, 0.0f) ),
69   mItemPushedSignal( ),
70   mItemPoppedSignal( )
71 {
72 }
73
74 NavigationControl::~NavigationControl()
75 {
76   // Clear all the items in the stack, forces their destruction before NavigationControl is destroyed.
77   mItemStack.clear();
78 }
79
80 void NavigationControl::OnInitialize()
81 {
82   //create layers for display background, current item, and bars respectively
83   mBackgroundLayer = CreateLayer();
84   mContentLayer = CreateLayer();
85   mBarLayer = CreateLayer();
86   mPopupLayer = CreateLayer();
87 }
88
89 void NavigationControl::OnControlChildAdd( Actor& child )
90 {
91   Toolkit::Page page = Toolkit::Page::DownCast(child);
92
93   // If it's a page then store it locally, Off stage.
94   if(page)
95   {
96     mUnpushedItems.push_back(page);
97
98     // Orphan it until needed later during "push".
99     Self().Remove( child );
100   }
101 }
102
103 Toolkit::NavigationControl NavigationControl::New()
104 {
105   // Create the implementation, temporarily owned by this handle on stack
106   IntrusivePtr< NavigationControl > internalNavigationControl = new NavigationControl();
107
108   // Pass ownership to CustomActor handle
109   Toolkit::NavigationControl navigationControl( *internalNavigationControl );
110
111   // Second-phase init of the implementation
112   // This can only be done after the CustomActor connection has been made...
113   internalNavigationControl->Initialize();
114
115   return navigationControl;
116 }
117
118 void NavigationControl::OnStageConnection()
119 {
120   //only works when navigation control is already on stage!
121   mContentLayer.RaiseAbove( mBackgroundLayer );
122   mBarLayer.RaiseAbove( mContentLayer );
123   mPopupLayer.RaiseAbove( mBarLayer );
124   Self().SetSensitive(true);
125   SetKeyInputFocus();
126 }
127
128 void NavigationControl::PushItem( Toolkit::Page page )
129 {
130   // check the uninitialized item
131   // check the duplicated push for the top item
132   if(!page || page == mCurrentItem)
133   {
134     return;
135   }
136
137   if( mCurrentItem )
138   {
139     mContentLayer.Remove( mCurrentItem );
140   }
141
142   //push the new item into the stack and show it
143   mItemStack.push_back(page);
144   mCurrentItem = page;
145   mContentLayer.Add(page);
146   mCurrentItem.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION);
147
148   //set up the popup menu which would response to the KEY_MENU
149   SetupPopupMenu();
150
151   //Emit singal
152   Toolkit::NavigationControl handle( GetOwner() );
153   mItemPushedSignal.Emit(handle, page);
154 }
155
156 Toolkit::Page NavigationControl::PopItem()
157 {
158   // cannot pop out the bottom-most item
159   Toolkit::Page poppedItem;
160   if(mItemStack.size() > 1)
161   {
162     // pop out the top item of the stack and show the new item right under the old one.
163     mContentLayer.Remove(mCurrentItem);
164     poppedItem = mItemStack.back();
165     mItemStack.pop_back();
166     mCurrentItem = mItemStack.back();
167     mContentLayer.Add(mCurrentItem);
168
169     //set up the popup menu which would response to the KEY_MENU
170     SetupPopupMenu();
171   }
172
173   //Emit signal
174   Toolkit::NavigationControl handle( GetOwner() );
175   mItemPoppedSignal.Emit(handle, poppedItem);
176
177   return poppedItem;
178 }
179
180 size_t NavigationControl::GetItemCount() const
181 {
182   return mItemStack.size();
183 }
184
185 Toolkit::Page NavigationControl::GetItem(std::size_t index) const
186 {
187   DALI_ASSERT_ALWAYS( index < mItemStack.size() );
188   return mItemStack[index];
189 }
190
191 Toolkit::Page NavigationControl::GetCurrentItem() const
192 {
193   return mCurrentItem;
194 }
195
196 void NavigationControl::SetBackground( Actor background)
197 {
198   // It removes the old background
199   if( mBackground )
200   {
201     mBackgroundLayer.Remove( mBackground );
202   }
203   mBackgroundLayer.Add( background );
204   mBackground = background;
205   mBackground.SetSize( mControlSize );
206 }
207
208 void NavigationControl::CreateNavigationToolBar(Toolkit::NaviToolBarStyle toolBarStylePortrait,
209                                                 Toolkit::NaviToolBarStyle toolBarStyleLandscape )
210 {
211   // Set a navigation tool bar at the bottom of the navigation frame
212   // the controls on the tool bar will update automatically when item is pushed or popped by responding to the signals
213   mToolBar = new NavigationToolBar(*this, toolBarStylePortrait, toolBarStyleLandscape);
214 }
215
216 void NavigationControl::CreateNavigationTitleBar(Toolkit::NaviTitleBarStyle titleBarStylePortrait,
217                                                  Toolkit::NaviTitleBarStyle titleBarStyleLandscape)
218 {
219   // Set a navigation title bar at the top of the navigation frame
220   // the tile/subtitle/titl icon/buttons will update automatically when item is pushed or popped by responding to the signals
221   mTitleBar = new NavigationTitleBar(*this, titleBarStylePortrait, titleBarStyleLandscape);
222 }
223
224 void NavigationControl::OrientationChanged( int angle )
225 {
226   if( mOrientationAngle != angle )
227   {
228     Vector2 targetSize = Vector2(GetSizeSet());
229
230     // checking to see if changing from landscape -> portrait, or portrait -> landscape
231     if( mOrientationAngle%180 != angle%180 )
232     {
233       targetSize = Vector2( targetSize.height, targetSize.width );
234     }
235
236     mOrientationAngle = angle;
237
238     switch(angle)
239     {
240       case 0:
241       {
242         mItemPositionCoefficient = Vector3(0.0f, 1.0f, 0.0f);
243         break;
244       }
245       case 90:
246       {
247         mItemPositionCoefficient = Vector3(1.0f, 0.0f, 0.0f);
248         break;
249       }
250       case 180:
251       {
252         mItemPositionCoefficient = Vector3(0.0f, -1.0f, 0.0f);
253         break;
254       }
255       case 270:
256       {
257         mItemPositionCoefficient = Vector3(-1.0f, 0.0f, 0.0f);
258         break;
259       }
260       default:
261       {
262         DALI_ASSERT_ALWAYS(false);
263         break;
264       }
265     }
266
267     Actor self = Self();
268     Animation animation = Animation::New( mOrientationAnimationDuration );
269     animation.AnimateTo( Property( self, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( -angle ) ), Vector3::ZAXIS ), mOrientationAnimationAlphaFunc );
270     animation.Play();
271
272     self.SetSize( targetSize );
273
274     RelayoutRequest();
275   }
276 }
277
278 void NavigationControl::SetOrientationRotateAnimation( float duration, AlphaFunction alphaFunc)
279 {
280   mOrientationAnimationDuration = duration;
281   mOrientationAnimationAlphaFunc = alphaFunc;
282 }
283
284 Layer NavigationControl::GetBarLayer() const
285 {
286   return mBarLayer;
287 }
288
289 void NavigationControl::OnRelayout( const Vector2& size, RelayoutContainer& container )
290 {
291   const Vector2 setSize( size );
292
293   if( mCurrentItem )
294   {
295     // always set the current item to fully occupy navigationControl space apart from the bars,
296     // here the bars might be hidden if the current item does not need them
297     float positionOffset = 0.0f;
298     float sizeShrink = 0.0f;
299     if(mTitleBar)
300     {
301       positionOffset += mTitleBar->GetBarHeight()*0.5f;
302       sizeShrink += mTitleBar->GetBarHeight();
303     }
304     if(mToolBar)
305     {
306       positionOffset -= mToolBar->GetBarHeight()*0.5f;
307       sizeShrink += mToolBar->GetBarHeight();
308     }
309     mCurrentItem.SetPosition( mItemPositionCoefficient * positionOffset);
310     Vector2 itemSize( setSize.x, setSize.y-sizeShrink );
311
312     container.Add( mCurrentItem, itemSize );
313   }
314
315   container.Add( mBarLayer, setSize );
316   container.Add( mPopupLayer, setSize );
317 }
318
319 void NavigationControl::OnControlSizeSet( const Vector3& size )
320 {
321   if( mControlSize == Vector2(size) )
322   {
323     return;
324   }
325   mControlSize = Vector2(size);
326
327   mBarLayer.SetSize(mControlSize);
328   mPopupLayer.SetSize(mControlSize);
329
330   if( mBackground )
331   {
332     mBackground.SetSize( mControlSize );
333   }
334   if( mToolBar )
335   {
336     mToolBar->ScaleStyleUpdate( mControlSize, mOrientationAngle );
337   }
338   if( mTitleBar )
339   {
340     mTitleBar->ScaleStyleUpdate( mControlSize, mOrientationAngle );
341   }
342 }
343
344 bool NavigationControl::OnKeyEvent( const KeyEvent& event )
345 {
346   bool consumed = false;
347
348   if(event.state == KeyEvent::Down)
349   {
350     if(event.keyCode == 96 ) // F12 == for test
351     //if( event.keyCode == Dali::DALI_KEY_BACK || event.keyCode == Dali::DALI_KEY_ESCAPE )
352     {
353       if( mPopupMenu && mPopupMenu.IsSensitive() ) // State:POPUP_SHOW
354       {
355         mPopupMenu.Hide();
356         consumed = true;
357       }
358       else if(PopItem())
359       {
360         consumed = true;
361       }
362     }
363
364     if( mPopupMenu && event.keyCode == 9)
365     //if( mPopupMenu && ( event.keyCode == Dali::DALI_KEY_MENU  || event.keyCode == Dali::DALI_KEY_SEND ) )
366     //Todo: replace with dali key enum after the mapping between X key definition and dali key enum is implemented in dali-adapto
367     //if( mPopupMenu && event.keyPressedName == "XF86Send" )
368     {
369       if( !mPopupMenu.IsSensitive() ) // State: POPUP_HIDE
370       {
371         mPopupMenu.Show();
372       }
373       else // State:POPUP_SHOW
374       {
375         mPopupMenu.Hide();
376       }
377       consumed = true;
378     }
379   }
380
381   return consumed;
382 }
383
384 Layer NavigationControl::CreateLayer()
385 {
386   Layer layer = Layer::New();
387   layer.SetPositionInheritanceMode(USE_PARENT_POSITION);
388   Self().Add(layer);
389   return layer;
390 }
391
392 void NavigationControl::SetupPopupMenu()
393 {
394   if(mPopupMenu)
395   {
396     mPopupLayer.Remove( mPopupMenu );
397   }
398   mPopupMenu = mCurrentItem.GetPopupMenu();
399   if( mPopupMenu )
400   {
401     mPopupLayer.Add( mPopupMenu );
402     mPopupMenu.OutsideTouchedSignal().Connect(this, &NavigationControl::OnPopupTouchedOutside);
403   }
404 }
405
406 void NavigationControl::OnPopupTouchedOutside()
407 {
408   if( mPopupMenu )
409   {
410     mPopupMenu.Hide();
411   }
412 }
413
414 Toolkit::NavigationControl::ItemPushedSignalType& NavigationControl::ItemPushedSignal()
415 {
416   return mItemPushedSignal;
417 }
418
419 Toolkit::NavigationControl::ItemPoppedSignalType& NavigationControl::ItemPoppedSignal()
420 {
421   return mItemPoppedSignal;
422 }
423
424 bool NavigationControl::DoAction( BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes )
425 {
426   bool ret = false;
427
428   Dali::BaseHandle handle( object );
429   Toolkit::NavigationControl control = Toolkit::NavigationControl::DownCast( handle );
430   DALI_ASSERT_ALWAYS( control );
431
432   if( 0 == strcmp( actionName.c_str(), ACTION_PUSH ) )
433   {
434     for( PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter )
435     {
436       const Property::Value& value = *iter;
437
438       DALI_ASSERT_ALWAYS( value.GetType() == Property::STRING );
439       std::string itemName = value.Get<std::string>();
440
441       for( std::list<Toolkit::Page>::iterator itemsIter = GetImpl( control ).mUnpushedItems.begin(); itemsIter != GetImpl( control ).mUnpushedItems.end(); ++itemsIter )
442       {
443         Toolkit::Page page = *itemsIter;
444         if( page.GetName() == itemName )
445         {
446           GetImpl( control ).PushItem( page );
447           ret = true;
448           break;
449         }
450       }
451     }
452   }
453   else if( 0 == strcmp( actionName.c_str(), ACTION_POP ) )
454   {
455     GetImpl( control ).PopItem();
456
457     ret = true;
458   }
459
460   return ret;
461 }
462
463 } // namespace Internal
464
465 } // namespace Toolkit
466
467 } // namespace Dali