Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / relayout-controller-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 "relayout-controller-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/common/stage.h>
24 #include <dali/integration-api/debug.h>
25
26 #if defined(DEBUG_ENABLED)
27 #include <sstream>
28 #endif // defined(DEBUG_ENABLED)
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 namespace Internal
37 {
38
39 namespace
40 {
41 #if defined(DEBUG_ENABLED)
42
43 Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_CONTROLLER") );
44
45 /**
46  * Prints out all the children of the given actor when debug is enabled.
47  *
48  * @param[in]  actor  The actor whose children to print.
49  * @param[in]  level  The number of " | " to put in front of the children.
50  */
51 void PrintChildren( Actor actor, int level )
52 {
53   std::ostringstream output;
54
55   for ( int t = 0; t < level; ++t )
56   {
57     output << " | ";
58   }
59
60   output << actor.GetTypeName();
61
62   output << " - Pos: " << actor.GetCurrentPosition() << " Size: " << actor.GetCurrentSize() << ",";
63
64   output << " (" << actor.GetObjectPtr() << ")" << std::endl;
65
66   DALI_LOG_INFO( gLogFilter, Debug::Verbose, output.str().c_str() );
67
68   ++level;
69   unsigned int numChildren = actor.GetChildCount();
70   for( unsigned int i=0; i<numChildren; ++i )
71   {
72     PrintChildren( actor.GetChildAt(i), level );
73   }
74   --level;
75 }
76
77 /**
78  * Prints the entire hierarchy of the scene.
79  */
80 void PrintHierarchy()
81 {
82   if ( gLogFilter->IsEnabledFor( Debug::Verbose ) )
83   {
84     PrintChildren( Stage().GetCurrent().GetRootLayer(), 0 );
85   }
86 }
87
88 #define PRINT_HIERARCHY PrintHierarchy()
89
90 #else // defined(DEBUG_ENABLED)
91
92 #define PRINT_HIERARCHY
93
94 #endif // defined(DEBUG_ENABLED)
95
96 /**
97  * Sets the target to source if the individual elements of source are NOT zero.
98  *
99  * @param[out]  target  The Vector2 elements to set if the source Vector2 elements are not 0.
100  * @param[in]   source  The Vector2 elements that are to be set to the target Vector2.
101  */
102 void SetIfNotZero( Vector2& target, const Vector2& source )
103 {
104   // Only set the width if it is non zero.
105   if ( !EqualsZero( source.width ) )
106   {
107     target.width  = source.width;
108   }
109
110   // Only set the height if it is non zero.
111   if ( !EqualsZero( source.height ) )
112   {
113     target.height = source.height;
114   }
115 }
116
117 /**
118  * Finds controls in the hierarchy of actor. It descends the tree if the actor has more Actors.
119  * If it is a control, it no longer descends the tree.
120  *
121  * @param[in]  actor  The actor in which controls should be found.
122  * @param[in]  size   The size that this actor and its children should be.
123  */
124 void FindControls( Actor actor, ControlStack& controls, Vector2 size )
125 {
126   Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
127   if( control )
128   {
129     // If the control size has been set by the application / control, then we should try and honour that.
130     Vector2 controlSetSize( control.GetImplementation().GetSizeSet() );
131
132     // Only set the width and height if they are non zero.
133     SetIfNotZero( size, controlSetSize );
134
135     controls.push_back( ControlSizePair( control, size ) );
136   }
137   else
138   {
139     unsigned int numChildren = actor.GetChildCount();
140     for( unsigned int i=numChildren; i>0; --i )
141     {
142       FindControls( actor.GetChildAt(i-1), controls, size );
143     }
144   }
145 }
146
147 /**
148  * Pushes the controls in the container, to the stack.
149  *
150  * @param[in,out]  controlStack  The stack to push controls to.
151  * @param[in]      container     The container to push controls from.
152  */
153 void PushToStack( ControlStack& controlStack, const ActorSizeContainer& container )
154 {
155   for ( ActorSizeContainer::const_reverse_iterator iter = container.rbegin(), endIter = container.rend(); iter != endIter; ++iter )
156   {
157     FindControls( iter->first, controlStack, iter->second );
158   }
159 }
160
161 } // unnamed namespace
162
163 RelayoutControllerImpl::RelayoutControllerImpl( bool& relayoutFlag )
164 : mRelayoutFlag( relayoutFlag ),
165   mRelayoutConnection( false )
166 {
167   // make space for 32 controls to avoid having to copy construct a lot in the beginning
168   mControlStack.reserve( 32 );
169   mSizecontainer.reserve( 32 );
170 }
171
172 RelayoutControllerImpl::~RelayoutControllerImpl()
173 {
174 }
175
176 void RelayoutControllerImpl::Request()
177 {
178   //TODO use Relayout Request to set up logic to optimize relayout of the actors/controls in the scene
179
180   if( !mRelayoutConnection )
181   {
182     Stage stage = Stage::GetCurrent();
183     stage.EventProcessingFinishedSignal().Connect( this, &RelayoutControllerImpl::Relayout );
184     mRelayoutConnection = true;
185   }
186 }
187
188 void RelayoutControllerImpl::Relayout()
189 {
190   // only do something when requested
191   if( mRelayoutFlag )
192   {
193     // clear the flag as we're now doing the relayout
194     mRelayoutFlag = false;
195     PRINT_HIERARCHY;
196
197     mControlStack.clear(); // we do not release memory, just empty the container
198
199     // 1. Finds all top-level controls from the root actor and allocate them the size of the stage
200     //    These controls are paired with the stage size and added to the stack.
201     FindControls( Stage().GetCurrent().GetRootLayer(), mControlStack, Stage::GetCurrent().GetSize() );
202
203     // 2. Iterate through the stack until it's empty.
204     while ( !mControlStack.empty() )
205     {
206       ControlSizePair pair ( mControlStack.back() );
207       Toolkit::Control control ( pair.first );
208       Vector2 size ( pair.second );
209       mControlStack.pop_back();
210
211       DALI_LOG_INFO( gLogFilter, Debug::General, "Allocating %p (%.2f, %.2f)\n", control.GetObjectPtr(), size.width, size.height );
212
213       mSizecontainer.clear();
214       // 3. Negotiate the size with the current control. Pass it an empty container which the control
215       //    has to fill with all the actors it has not done any size negotiation for.
216       control.GetImplementation().NegotiateSize( size, mSizecontainer );
217
218       // 4. Push the controls from the actors in the container to the stack.
219       PushToStack( mControlStack, mSizecontainer );
220     }
221   }
222   // should not disconnect the signal as that causes some control size negotiations to not work correctly
223   // this algorithm needs more optimization as well
224 }
225
226 } // namespace Internal
227
228 } // namespace Toolkit
229
230 } // namespace Dali