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