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