Merged with Tizen Branch ( builds )
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / tool-bar / tool-bar-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 "tool-bar-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/image-actor.h>
23 #include <dali/public-api/animation/constraints.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/controls/alignment/alignment.h>
29 #include <dali-toolkit/public-api/controls/table-view/table-view.h>
30
31 namespace Dali
32 {
33
34 namespace Toolkit
35 {
36
37 namespace Internal
38 {
39
40 namespace
41 {
42
43 BaseHandle Create()
44 {
45   return Toolkit::ToolBar::New();
46 }
47
48 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ToolBar, Toolkit::Control, Create )
49 DALI_TYPE_REGISTRATION_END()
50
51 const float DEFAULT_RELATIVE_SIZE( 0.1f );
52 const Toolkit::Alignment::Type DEFAULT_ALIGNMENT( Toolkit::Alignment::HorizontalLeft );
53 } // namespace
54
55 Toolkit::ToolBar ToolBar::New()
56 {
57   // Create the implementation, temporarily owned on stack
58   IntrusivePtr< ToolBar > internalToolBar = new ToolBar();
59
60   // Pass ownership to Toolkit::Toolbar
61   Toolkit::ToolBar toolBar( *internalToolBar );
62
63   // Second-phase init of the implementation
64   // This can only be done after the CustomActor connection has been made...
65   internalToolBar->Initialize();
66
67   return toolBar;
68 }
69
70 void ToolBar::SetBackground( Actor background )
71 {
72   Lock lock( mInitializing );
73
74   // ToolBar image
75   background.SetParentOrigin( Dali::ParentOrigin::TOP_CENTER );
76   background.SetAnchorPoint( Dali::AnchorPoint::TOP_CENTER );
77   background.SetSize( Vector2( mToolBarSize.width, mToolBarSize.height ) );
78
79   ImageActor renderableActor = ImageActor::DownCast( background );
80   if ( renderableActor )
81   {
82     renderableActor.SetSortModifier( 1.f );
83   }
84
85   Self().Add( background );
86   mBackground = background;
87 }
88
89 void ToolBar::AddControl( Actor control, float relativeSize, Toolkit::Alignment::Type alignment, const Toolkit::Alignment::Padding& padding )
90 {
91   // Work out index and update bases and offsets for further insertions.
92   unsigned int index = 0;
93   switch( alignment )
94   {
95     case Toolkit::Alignment::HorizontalLeft:
96     {
97       index = mLeftOffset;
98       ++mLeftOffset;
99       ++mCenterBase;
100       ++mRightBase;
101       break;
102     }
103     case Toolkit::Alignment::HorizontalCenter:
104     {
105       index = mCenterBase + mCenterOffset;
106       ++mCenterOffset;
107       ++mRightBase;
108       break;
109     }
110     case Toolkit::Alignment::HorizontalRight:
111     {
112       index = mRightBase - mRightOffset;
113       ++mRightBase;
114       ++mRightOffset;
115       break;
116     }
117     default:
118     {
119       DALI_ASSERT_ALWAYS( false );
120     }
121   }
122
123   // Create a new column for the new control.
124   mLayout.InsertColumn( index );
125
126   // Create an alignment container where to place the control.
127   Toolkit::Alignment alignmentContainer = Toolkit::Alignment::New( alignment );
128   alignmentContainer.SetSizeScalePolicy( SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
129   alignmentContainer.SetPadding( padding );
130   alignmentContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
131   alignmentContainer.Add( control );
132
133   // Insert the control in the table view.
134   mLayout.AddChild( alignmentContainer, Toolkit::TableView::CellPosition( 0, index ) );
135   mLayout.SetRelativeWidth( index, relativeSize );
136
137   // Relate control and alignmentContainer in order to allow removing controls.
138   mControls[control] = alignmentContainer;
139
140   // Update accumulated relative space.
141   mAccumulatedRelativeSpace += relativeSize;
142
143   // Update spaces between left, center and right groups of controls.
144   switch( alignment )
145   {
146     case Toolkit::Alignment::HorizontalLeft:
147     {
148       mLeftRelativeSpace -= relativeSize;
149       if ( mLeftRelativeSpace < 0.f )
150       {
151         mLeftRelativeSpace = 0.f;
152       }
153       break;
154     }
155     case Toolkit::Alignment::HorizontalCenter:
156     {
157       mLeftRelativeSpace -= 0.5f * relativeSize;
158       if ( mLeftRelativeSpace < 0.f )
159       {
160         mLeftRelativeSpace = 0.f;
161       }
162       mRightRelativeSpace -= 0.5f * relativeSize;
163       if ( mRightRelativeSpace < 0.f )
164       {
165         mRightRelativeSpace = 0.f;
166       }
167       break;
168     }
169     case Toolkit::Alignment::HorizontalRight:
170     {
171       mRightRelativeSpace -= relativeSize;
172       if ( mRightRelativeSpace < 0.f )
173       {
174         mRightRelativeSpace = 0.f;
175       }
176       break;
177     }
178     default:
179     {
180       DALI_ASSERT_ALWAYS( false );
181     }
182   }
183
184   mLayout.SetRelativeWidth( mLeftOffset, mLeftRelativeSpace );
185   mLayout.SetRelativeWidth( mCenterBase + mCenterOffset, mRightRelativeSpace );
186 }
187
188 void ToolBar::RemoveControl( Actor control )
189 {
190   Toolkit::TableView::CellPosition position;
191
192   // Find the alignment where the control is placed.
193   std::map<Actor,Toolkit::Alignment>::iterator it = mControls.find( control );
194
195   if( ( it != mControls.end() ) && ( mLayout.FindChildPosition( it->second, position ) ) )
196   {
197     // Update accumulated relative space.
198     mAccumulatedRelativeSpace -= mLayout.GetRelativeWidth( position.columnIndex );
199
200     // Update spaces between left, center and right groups of controls.
201     if( 1.0 > mAccumulatedRelativeSpace )
202     {
203       Toolkit::Alignment::Type alignment = Toolkit::Alignment::HorizontalLeft;
204       if( position.columnIndex < mLeftOffset )
205       {
206         alignment = Toolkit::Alignment::HorizontalLeft;
207       }
208       else if( ( position.columnIndex > mLeftOffset ) && ( position.columnIndex < mCenterBase + mCenterOffset ) )
209       {
210         alignment = Toolkit::Alignment::HorizontalCenter;
211       }
212       else if( position.columnIndex > mCenterBase + mCenterOffset )
213       {
214         alignment = Toolkit::Alignment::HorizontalRight;
215       }
216       else
217       {
218         DALI_ASSERT_ALWAYS( false );
219       }
220
221       float relativeSize = mLayout.GetRelativeWidth( position.columnIndex );
222
223       switch( alignment )
224       {
225         case Toolkit::Alignment::HorizontalLeft:
226         {
227           mLeftRelativeSpace += relativeSize;
228           if ( mLeftRelativeSpace < 0.f )
229           {
230             mLeftRelativeSpace = 0.f;
231           }
232           break;
233         }
234         case Toolkit::Alignment::HorizontalCenter:
235         {
236           mLeftRelativeSpace += 0.5f * relativeSize;
237           if ( mLeftRelativeSpace < 0.f )
238           {
239             mLeftRelativeSpace = 0.f;
240           }
241           mRightRelativeSpace += 0.5f * relativeSize;
242           if ( mRightRelativeSpace < 0.f )
243           {
244             mRightRelativeSpace = 0.f;
245           }
246           break;
247         }
248         case Toolkit::Alignment::HorizontalRight:
249         {
250           mRightRelativeSpace += relativeSize;
251           if ( mRightRelativeSpace < 0.f )
252           {
253             mRightRelativeSpace = 0.f;
254           }
255           break;
256         }
257         default:
258         {
259           DALI_ASSERT_ALWAYS( false );
260         }
261       }
262       mLayout.SetRelativeWidth( mLeftOffset, mLeftRelativeSpace );
263       mLayout.SetRelativeWidth( mCenterBase + mCenterOffset, mRightRelativeSpace );
264     }
265
266     // Remove alignment as parent of control.
267     it->second.Remove( control );
268
269     // Remove the relationship between control and alignment.
270     mControls.erase( it );
271
272     // Remove column from tableview.
273     mLayout.DeleteColumn( position.columnIndex );
274
275     // Update bases and offsets.
276     if( position.columnIndex < mCenterBase )
277     {
278       // Control is on the left side. Decrease left offset and center and right bases.
279       --mLeftOffset;
280       --mCenterBase;
281       --mRightBase;
282     }
283     else if( position.columnIndex < mCenterBase + mCenterOffset )
284     {
285       // Control is on the center side. Decrease center offset and right base.
286       --mCenterOffset;
287       --mRightBase;
288     }
289     else
290     {
291       // Control is on the right side. Decrease right base and right offset.
292       --mRightBase;
293       --mRightOffset;
294     }
295   }
296 }
297
298 ToolBar::ToolBar()
299 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
300   mLayout(),
301   mLeftOffset( 0 ),
302   mCenterBase( 1 ),
303   mCenterOffset( 0 ),
304   mRightBase( 2 ),
305   mRightOffset( 0 ),
306   mLeftRelativeSpace( 0.5f ),
307   mRightRelativeSpace( 0.5f ),
308   mAccumulatedRelativeSpace( 0.f ),
309   mInitializing( false ),
310   mControls()
311 {
312 }
313
314 ToolBar::~ToolBar()
315 {
316 }
317
318 void ToolBar::OnInitialize()
319 {
320   Lock lock( mInitializing );
321
322   // Layout
323   mLayout = Toolkit::TableView::New( 1, 1 );
324   mLayout.SetName( "TOOLBAR_LAYOUT" );
325   mLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
326   mLayout.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
327
328   Self().Add( mLayout );
329
330   // Add two default actors to create spaces between controls grouped on the left, center and right.
331   Actor leftSpace = Actor::New();
332   Actor rightSpace = Actor::New();
333   mLayout.AddChild( leftSpace, Toolkit::TableView::CellPosition( 0, 0 ) );
334   mLayout.AddChild( rightSpace, Toolkit::TableView::CellPosition( 0, 1 ) );
335   mLayout.SetRelativeWidth( 0, mLeftRelativeSpace );
336   mLayout.SetRelativeWidth( 1, mRightRelativeSpace );
337 }
338
339 void ToolBar::OnControlChildAdd(Actor& child)
340 {
341   if( !mInitializing )
342   {
343     // An actor is being added through the Actor's API.
344
345     // Remove child from tool bar actor and insert it in table view with some 'default' values
346     if ( child && child.GetParent() )
347     {
348       child.GetParent().Remove( child );
349     }
350
351     AddControl( child, DEFAULT_RELATIVE_SIZE, DEFAULT_ALIGNMENT, Toolkit::ToolBar::DEFAULT_PADDING );
352   }
353
354   // No OnControlChildRemove method required because Actors are added to the mLayout table view, so if an
355   // actor is removed using the Actor::RemoveChild method it will not remove anything because the
356   // actor is in mLayout not in Self().
357 }
358
359 void ToolBar::OnControlSizeSet( const Vector3& targetSize )
360 {
361   mToolBarSize = targetSize;
362   mBackground.SetSize( Vector2( mToolBarSize.width, mToolBarSize.height ) );
363 }
364
365 } // namespace Internal
366
367 } // namespace Toolkit
368
369 } // namespace Dali