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