Remove unnecessarily exported signals and action names
[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
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/controls/navigation-frame/navigation-tool-bar.h>
28 #include <dali-toolkit/internal/controls/navigation-frame/navigation-title-bar.h>
29 #include <dali-toolkit/internal/controls/relayout-controller.h>
30 #include <dali-toolkit/public-api/focus-manager/focus-manager.h>
31
32 namespace Dali
33 {
34
35 namespace Toolkit
36 {
37
38 namespace Internal
39 {
40
41 namespace // to register type
42 {
43
44 // Actions
45
46 const char* const ACTION_PUSH = "push";
47 const char* const ACTION_POP =  "pop";
48
49 BaseHandle Create()
50 {
51   return Toolkit::NavigationControl::New();
52 }
53
54 TypeRegistration mType( typeid( Toolkit::NavigationControl ), typeid( Toolkit::Control ), Create );
55
56 TypeAction a1( mType, ACTION_PUSH, &NavigationControl::DoAction );
57 TypeAction a2( mType, ACTION_POP, &NavigationControl::DoAction );
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     Animation animation = Animation::New( mOrientationAnimationDuration );
268     animation.RotateTo( Self(), Degree( -angle ), Vector3::ZAXIS, mOrientationAnimationAlphaFunc );
269     animation.Play();
270
271     Self().SetSize( targetSize );
272
273     RelayoutRequest();
274   }
275 }
276
277 void NavigationControl::SetOrientationRotateAnimation( float duration, AlphaFunction alphaFunc)
278 {
279   mOrientationAnimationDuration = duration;
280   mOrientationAnimationAlphaFunc = alphaFunc;
281 }
282
283 Layer NavigationControl::GetBarLayer() const
284 {
285   return mBarLayer;
286 }
287
288 void NavigationControl::OnRelayout( const Vector2& size, ActorSizeContainer& container )
289 {
290   const Vector2 setSize( size );
291
292   if( mCurrentItem )
293   {
294     // always set the current item to fully occupy navigationControl space apart from the bars,
295     // here the bars might be hidden if the current item does not need them
296     float positionOffset = 0.0f;
297     float sizeShrink = 0.0f;
298     if(mTitleBar)
299     {
300       positionOffset += mTitleBar->GetBarHeight()*0.5f;
301       sizeShrink += mTitleBar->GetBarHeight();
302     }
303     if(mToolBar)
304     {
305       positionOffset -= mToolBar->GetBarHeight()*0.5f;
306       sizeShrink += mToolBar->GetBarHeight();
307     }
308     mCurrentItem.SetPosition( mItemPositionCoefficient * positionOffset);
309     Vector2 itemSize( setSize.x, setSize.y-sizeShrink );
310
311     Relayout(mCurrentItem, itemSize, container);
312   }
313
314   container.push_back(ActorSizePair( mBarLayer, setSize ));
315   container.push_back(ActorSizePair( mPopupLayer, setSize ));
316 }
317
318 void NavigationControl::OnControlSizeSet( const Vector3& size )
319 {
320   if( mControlSize == Vector2(size) )
321   {
322     return;
323   }
324   mControlSize = Vector2(size);
325
326   mBarLayer.SetSize(mControlSize);
327   mPopupLayer.SetSize(mControlSize);
328
329   if( mBackground )
330   {
331     mBackground.SetSize( mControlSize );
332   }
333   if( mToolBar )
334   {
335     mToolBar->ScaleStyleUpdate( mControlSize, mOrientationAngle );
336   }
337   if( mTitleBar )
338   {
339     mTitleBar->ScaleStyleUpdate( mControlSize, mOrientationAngle );
340   }
341 }
342
343 bool NavigationControl::OnKeyEvent( const KeyEvent& event )
344 {
345   bool consumed = false;
346
347   if(event.state == KeyEvent::Down)
348   {
349     if(event.keyCode == 96 ) // F12 == for test
350     //if( event.keyCode == Dali::DALI_KEY_BACK || event.keyCode == Dali::DALI_KEY_ESCAPE )
351     {
352       if( mPopupMenu && mPopupMenu.IsSensitive() ) // State:POPUP_SHOW
353       {
354         mPopupMenu.Hide();
355         consumed = true;
356       }
357       else if(PopItem())
358       {
359         consumed = true;
360       }
361     }
362
363     if( mPopupMenu && event.keyCode == 9)
364     //if( mPopupMenu && ( event.keyCode == Dali::DALI_KEY_MENU  || event.keyCode == Dali::DALI_KEY_SEND ) )
365     //Todo: replace with dali key enum after the mapping between X key definition and dali key enum is implemented in dali-adapto
366     //if( mPopupMenu && event.keyPressedName == "XF86Send" )
367     {
368       if( !mPopupMenu.IsSensitive() ) // State: POPUP_HIDE
369       {
370         mPopupMenu.Show();
371       }
372       else // State:POPUP_SHOW
373       {
374         mPopupMenu.Hide();
375       }
376       consumed = true;
377     }
378   }
379
380   return consumed;
381 }
382
383 Layer NavigationControl::CreateLayer()
384 {
385   Layer layer = Layer::New();
386   layer.SetPositionInheritanceMode(USE_PARENT_POSITION);
387   Self().Add(layer);
388   return layer;
389 }
390
391 void NavigationControl::SetupPopupMenu()
392 {
393   if(mPopupMenu)
394   {
395     mPopupLayer.Remove( mPopupMenu );
396   }
397   mPopupMenu = mCurrentItem.GetPopupMenu();
398   if( mPopupMenu )
399   {
400     mPopupLayer.Add( mPopupMenu );
401     mPopupMenu.OutsideTouchedSignal().Connect(this, &NavigationControl::OnPopupTouchedOutside);
402   }
403 }
404
405 void NavigationControl::OnPopupTouchedOutside()
406 {
407   if( mPopupMenu )
408   {
409     mPopupMenu.Hide();
410   }
411 }
412
413 Toolkit::NavigationControl::ItemPushedSignalType& NavigationControl::ItemPushedSignal()
414 {
415   return mItemPushedSignal;
416 }
417
418 Toolkit::NavigationControl::ItemPoppedSignalType& NavigationControl::ItemPoppedSignal()
419 {
420   return mItemPoppedSignal;
421 }
422
423 bool NavigationControl::DoAction( BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes )
424 {
425   bool ret = false;
426
427   Dali::BaseHandle handle( object );
428   Toolkit::NavigationControl control = Toolkit::NavigationControl::DownCast( handle );
429   DALI_ASSERT_ALWAYS( control );
430
431   if( 0 == strcmp( actionName.c_str(), ACTION_PUSH ) )
432   {
433     for( PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter )
434     {
435       const Property::Value& value = *iter;
436
437       DALI_ASSERT_ALWAYS( value.GetType() == Property::STRING );
438       std::string itemName = value.Get<std::string>();
439
440       for( std::list<Toolkit::Page>::iterator itemsIter = GetImpl( control ).mUnpushedItems.begin(); itemsIter != GetImpl( control ).mUnpushedItems.end(); ++itemsIter )
441       {
442         Toolkit::Page page = *itemsIter;
443         if( page.GetName() == itemName )
444         {
445           GetImpl( control ).PushItem( page );
446           ret = true;
447           break;
448         }
449       }
450     }
451   }
452   else if( 0 == strcmp( actionName.c_str(), ACTION_POP ) )
453   {
454     GetImpl( control ).PopItem();
455
456     ret = true;
457   }
458
459   return ret;
460 }
461
462 } // namespace Internal
463
464 } // namespace Toolkit
465
466 } // namespace Dali