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