(StyleManager) Create a style manager
[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 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 #include "navigation-control-impl.h"
19
20 //INTERNAL INCLUDES
21 #include <dali-toolkit/internal/controls/navigation-frame/navigation-tool-bar.h>
22 #include <dali-toolkit/internal/controls/navigation-frame/navigation-title-bar.h>
23 #include <dali-toolkit/internal/controls/relayout-controller.h>
24 #include <dali-toolkit/public-api/focus-manager/focus-manager.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 namespace // to register type
36 {
37 BaseHandle Create()
38 {
39   return Toolkit::NavigationControl::New();
40 }
41
42 TypeRegistration mType( typeid(Toolkit::NavigationControl), typeid(Toolkit::Control), Create );
43
44 TypeAction a1(mType, Toolkit::NavigationControl::ACTION_PUSH, &NavigationControl::DoAction);
45 TypeAction a2(mType, Toolkit::NavigationControl::ACTION_POP, &NavigationControl::DoAction);
46 }
47
48 NavigationControl::NavigationControl()
49 : Control( REQUIRES_TOUCH_EVENTS ),
50   mToolBar(NULL),
51   mTitleBar(NULL),
52   mOrientationAngle( 0 ),
53   mOrientationAnimationDuration( 1.0f ),
54   mOrientationAnimationAlphaFunc( AlphaFunctions::EaseOut ),
55   mItemPositionCoefficient( Vector3( 0.0f, 1.0f, 0.0f) ),
56   mItemPushedSignal( ),
57   mItemPoppedSignal( )
58 {
59 }
60
61 NavigationControl::~NavigationControl()
62 {
63   // Clear all the items in the stack, forces their destruction before NavigationControl is destroyed.
64   mItemStack.clear();
65 }
66
67 void NavigationControl::OnInitialize()
68 {
69   //create layers for display background, current item, and bars respectively
70   mBackgroundLayer = CreateLayer();
71   mContentLayer = CreateLayer();
72   mBarLayer = CreateLayer();
73   mPopupLayer = CreateLayer();
74 }
75
76 void NavigationControl::OnControlChildAdd( Actor& child )
77 {
78   Toolkit::Page page = Toolkit::Page::DownCast(child);
79
80   // If it's a page then store it locally, Off stage.
81   if(page)
82   {
83     mUnpushedItems.push_back(page);
84
85     // Orphan it until needed later during "push".
86     Self().Remove( child );
87   }
88 }
89
90 Toolkit::NavigationControl NavigationControl::New()
91 {
92   // Create the implementation, temporarily owned by this handle on stack
93   IntrusivePtr< NavigationControl > internalNavigationControl = new NavigationControl();
94
95   // Pass ownership to CustomActor handle
96   Toolkit::NavigationControl navigationControl( *internalNavigationControl );
97
98   // Second-phase init of the implementation
99   // This can only be done after the CustomActor connection has been made...
100   internalNavigationControl->Initialize();
101
102   return navigationControl;
103 }
104
105 void NavigationControl::OnStageConnection()
106 {
107   //only works when navigation control is already on stage!
108   mContentLayer.RaiseAbove( mBackgroundLayer );
109   mBarLayer.RaiseAbove( mContentLayer );
110   mPopupLayer.RaiseAbove( mBarLayer );
111   Self().SetSensitive(true);
112   SetKeyInputFocus();
113 }
114
115 void NavigationControl::PushItem( Toolkit::Page page )
116 {
117   // check the uninitialized item
118   // check the duplicated push for the top item
119   if(!page || page == mCurrentItem)
120   {
121     return;
122   }
123
124   if( mCurrentItem )
125   {
126     mContentLayer.Remove( mCurrentItem );
127   }
128
129   //push the new item into the stack and show it
130   mItemStack.push_back(page);
131   mCurrentItem = page;
132   mContentLayer.Add(page);
133   mCurrentItem.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION);
134
135   //set up the popup menu which would response to the KEY_MENU
136   SetupPopupMenu();
137
138   //Emit singal
139   Toolkit::NavigationControl handle( GetOwner() );
140   mItemPushedSignal.Emit(handle, page);
141 }
142
143 Toolkit::Page NavigationControl::PopItem()
144 {
145   // cannot pop out the bottom-most item
146   Toolkit::Page poppedItem;
147   if(mItemStack.size() > 1)
148   {
149     // pop out the top item of the stack and show the new item right under the old one.
150     mContentLayer.Remove(mCurrentItem);
151     poppedItem = mItemStack.back();
152     mItemStack.pop_back();
153     mCurrentItem = mItemStack.back();
154     mContentLayer.Add(mCurrentItem);
155
156     //set up the popup menu which would response to the KEY_MENU
157     SetupPopupMenu();
158   }
159
160   //Emit signal
161   Toolkit::NavigationControl handle( GetOwner() );
162   mItemPoppedSignal.Emit(handle, poppedItem);
163
164   return poppedItem;
165 }
166
167 size_t NavigationControl::GetItemCount() const
168 {
169   return mItemStack.size();
170 }
171
172 Toolkit::Page NavigationControl::GetItem(std::size_t index) const
173 {
174   DALI_ASSERT_ALWAYS( index < mItemStack.size() );
175   return mItemStack[index];
176 }
177
178 Toolkit::Page NavigationControl::GetCurrentItem() const
179 {
180   return mCurrentItem;
181 }
182
183 void NavigationControl::SetBackground( Actor background)
184 {
185   // It removes the old background
186   if( mBackground )
187   {
188     mBackgroundLayer.Remove( mBackground );
189   }
190   mBackgroundLayer.Add( background );
191   mBackground = background;
192   mBackground.SetSize( mControlSize );
193 }
194
195 void NavigationControl::CreateNavigationToolBar(Toolkit::NaviToolBarStyle toolBarStylePortrait,
196                                                 Toolkit::NaviToolBarStyle toolBarStyleLandscape )
197 {
198   // Set a navigation tool bar at the bottom of the navigation frame
199   // the controls on the tool bar will update automatically when item is pushed or popped by responding to the signals
200   mToolBar = new NavigationToolBar(*this, toolBarStylePortrait, toolBarStyleLandscape);
201 }
202
203 void NavigationControl::CreateNavigationTitleBar(Toolkit::NaviTitleBarStyle titleBarStylePortrait,
204                                                  Toolkit::NaviTitleBarStyle titleBarStyleLandscape)
205 {
206   // Set a navigation title bar at the top of the navigation frame
207   // the tile/subtitle/titl icon/buttons will update automatically when item is pushed or popped by responding to the signals
208   mTitleBar = new NavigationTitleBar(*this, titleBarStylePortrait, titleBarStyleLandscape);
209 }
210
211 void NavigationControl::OrientationChanged( int angle )
212 {
213   if( mOrientationAngle != angle )
214   {
215     Vector2 targetSize = Vector2(GetSizeSet());
216
217     // checking to see if changing from landscape -> portrait, or portrait -> landscape
218     if( mOrientationAngle%180 != angle%180 )
219     {
220       targetSize = Vector2( targetSize.height, targetSize.width );
221     }
222
223     mOrientationAngle = angle;
224
225     switch(angle)
226     {
227       case 0:
228       {
229         mItemPositionCoefficient = Vector3(0.0f, 1.0f, 0.0f);
230         break;
231       }
232       case 90:
233       {
234         mItemPositionCoefficient = Vector3(1.0f, 0.0f, 0.0f);
235         break;
236       }
237       case 180:
238       {
239         mItemPositionCoefficient = Vector3(0.0f, -1.0f, 0.0f);
240         break;
241       }
242       case 270:
243       {
244         mItemPositionCoefficient = Vector3(-1.0f, 0.0f, 0.0f);
245         break;
246       }
247       default:
248       {
249         DALI_ASSERT_ALWAYS(false);
250         break;
251       }
252     }
253
254     Animation animation = Animation::New( mOrientationAnimationDuration );
255     animation.SetDestroyAction( Animation::Bake );
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