Size negotiation patch 4: Remove SetRelayoutEnabled
[platform/core/uifw/dali-toolkit.git] / docs / content / programming-guide / size-negotiation-controls.h
1 /*! \page size-negotiation-controls Size Negotiation for Controls
2  *
3 <h2 class="pg">Overview</h2>
4
5 This document details how to create controls using the size negotiation API and is intended for UI control writters. For an introduction to
6 size negotiation please see the <i>Size Negotiation Programming Guide</i>.
7
8 The topics covered are:
9 - The Relayout Controller
10 - Resize Policies
11 - Creating a Control: Popups
12 - Size Negotiation API
13 - Creating a Control: TableView
14
15 <h2 class="pg">The Relayout Controller</h2>
16
17 <h3>Overview</h3>
18 The RelayoutController is an object that is private in DALi Core. It's main job is to take relayout requests from actors.
19 It can be enabled or disabled internally. If disabled, then all relayout requests are ignored. By default the relayout controller is disabled until just after the
20 initial application initialize. This allows the scene for an application to be created without generating many relayout requests. After the application
21 has initialized the scene, then the relayout controller is automatically enabled and a relayout request is called on the root of the scene. This request spreads down the scene
22 hierarchy and requests relayout on all actors that have size negotiation enabled.
23
24 Relayout requests are put in automatically when a property is changed on an actor or a change to the stage hierarchy is made and manual requests are usually not necessary.
25
26 <h2 class="pg">Resize Policies</h2>
27
28 In addition to the resize policies detailed in the Size Negotiation Programming Guide there is one additional policy available to control writers:
29
30 - ResizePolicy::USE_ASSIGNED_SIZE: Tells the actor to use the size that was passed into the size negotiation algorithm for it. This is used in the OnRelayout
31 method derived from Actor when passing back controls to be negotiated using the container argument to the method.
32
33 <h2 class="pg">Creating a Control: Popups</h2>
34
35 <h3>Initialization</h3>
36 Size negotiation is enabled on controls by default. If a control is desired to not have size negotiation enabled then simply pass in the
37 DISABLE_SIZE_NEGOTIATION flag into the Control constructor.
38
39 The other step to perform is to set default resize policies for width and height.
40
41 <h3>A Simple Example: Popup</h3>
42
43 This example shows how to set up a popup for use with size negotiation. The popup contains a layer to raise it above all other controls,
44 a semi-transparent full-screen backing image to dim the screen, a background image with a shadow border, and buttons that are positioned
45 and resized by the popup. The following screen shot shows an example popup.
46
47 \image html size-negotiation/PopupExample.png
48
49 The first step is to set the default resize policies. This is done in the OnInitialize method. In the following snippet the popup
50 is set to have a height resize policy of ResizePolicy::FIT_TO_CHILDREN. This assumes that the width of the popup will be specified by the user of
51 the popup and that the desired behaviour is to fit the height of the popup to the size of its content.
52 @code
53 void Popup::OnInitialize()
54 ...
55 Actor self = Self();
56 self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
57 @endcode
58 The popup will use a layer to place its content in. The layer is created and specified to fill the whole screen by using the following command.
59 @code
60 mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
61 @endcode
62 A half transparent backing image is added to the layer and told to fill the layer with the following.
63 @code
64 mBacking.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
65 @endcode
66 The popup control is added to the layer and a background image is specified to fill the size of the popup and add a border by the following.
67 @code
68 mBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
69 Vector3 border( mPopupStyle->backgroundOuterBorder.x, mPopupStyle->backgroundOuterBorder.z, 0.0f );
70 mBackgroundImage.SetSizeModeFactor( border );
71 @endcode
72 A table view is added to the popup to specify layout. It will fill to the width of the popup and expand/contract around its children cell heights.
73 @code
74 mPopupLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
75 mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
76 @endcode
77 Override the OnRelayout method to position and resize the buttons. The trick to this is that the buttons do not know they are part of a popup and are
78 about to be resized so could already have had their sizes negotiated. The call to PropagateRelayoutFlags on the button will ensure that it and all
79 its child dependents are ready for a new size negotiation pass. The container.Add call will add the button to the relayout queue to be processed this frame.
80 The buttonSize parameter is the desired size for the button. The desired size will only be set if the size policy of the button has already been changed to
81 ResizePolicy::USE_ASSIGNED_SIZE, which is what happens when a button is added to the popup.
82 @code
83 void Popup::AddButton( Toolkit::Button button )
84 ...
85 button.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::ALL_DIMENSIONS );
86 ...
87
88 void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
89 ...
90 button.SetPosition( buttonPosition );
91
92 button.PropagateRelayoutFlags();    // Reset relayout flags for relayout
93 container.Add( button, buttonSize );
94 ...
95 @endcode
96 Another aspect to the popup is that depending which resize policies are active on it then the inner table view requires different resize policies itself.
97 OnSetResizePolicy can be overridden to receive notice that the resize policy has changed on the control and action can be taken.
98 @code
99 void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
100 ...
101 if( policy == ResizePolicy::FIT_TO_CHILDREN )
102 {
103   // Make content fit to children
104   mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, dimension );
105   if( dimension & Dimension::HEIGHT )
106   {
107     mPopupLayout.SetFitHeight( 1 );
108   }
109 }
110 else
111 {
112   mPopupLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, dimension );
113   // Make the content cell fill the whole of the available space
114   if( dimension & Dimension::HEIGHT )
115   {
116     mPopupLayout.SetRelativeHeight( 1, 1.0f );
117   }
118 }
119 @endcode
120 Popup also implements the following methods for use with the relevant resize policies:
121 - GetNaturalSize
122 - GetHeightForWidth
123 - GetWidthForHeight
124
125 <h2 class="pg">Size Negotiation API</h2>
126
127 <h3>Base Class Methods</h3>
128
129 The base class methods are used to call functionality held in Actor and are defined in CustomActorImpl.
130
131 There is a RelayoutRequest method defined. This method is available for deriving controls to call when they would like themselves to be relaid out.
132 @code void RelayoutRequest() @endcode
133
134 <h3>Overridable Methods</h3>
135 These overridable methods in control provide customization points for the size negotiation algorithm.
136
137 <h4>Responding to the Change of Size on a Control</h4>
138
139 OnRelayout is called during the relayout process at the end of the frame immediately after the new size has been set on the actor. If the actor has calculated
140 the size of child actors then add them to container with their desired size and set the ResizePolicy::USE_ASSIGNED_SIZE resize policy on them.
141 At this point the size of the actor has been calculated so it is a good place to calculate positions of child actors etc.
142 @code virtual void OnRelayout( const Vector2& size, RelayoutContainer& container ) @endcode
143
144 The OnRelayoutSignal signal is raised after SetSize and OnRelayout have been called during the relayout processing at the end of the frame. If the control is deriving
145 from Control then the OnRelayout virtual is preferred over this signal. The signal is provided for instance when custom code needs to be run on the
146 children of an actor that is not a control.
147 @code OnRelayoutSignalType& OnRelayoutSignal() @endcode
148
149 The OnCalculateRelayoutSize is called right before the size is calculated for an actor's dimension during the size negotiation phase. At this point all other actors this actor is
150 dependent on have been negotiated so calculations depending on these actors can be performed before the size for this actor is calculated. Useful for container size calculations.
151 @code virtual void OnCalculateRelayoutSize( Dimension::Type dimension ) @endcode
152
153 OnLayoutNegotiated is called right after the size in a given dimension has been negotiated for an actor. This allows calculations to be performed in response to the change
154 in a given dimension but before OnRelayout is called.
155 @code virtual void OnLayoutNegotiated( float size, Dimension::Type dimension ) @endcode
156
157 <h4>Calculating Sizes</h4>
158
159 Calculate the natural size for this control. This will be called when a control's resize policy is set to USE_NATURAL_SIZE.
160 For example, TableView will calculated the size of the table given its various cell properties.
161 @code virtual Vector3 GetNaturalSize() @endcode
162
163 Given an input width return the correct height for this control. This will be called when the resize policy is set to ResizePolicy::DIMENSION_DEPENDENCY and
164 height has a dependency on width.
165 @code virtual float GetHeightForWidth( float width ) @endcode
166
167 Given the input height return the correct width for this control. This will be called when the resize policy is set to ResizePolicy::DIMENSION_DEPENDENCY and
168 width has a dependency on height.
169 @code virtual float GetWidthForHeight( float height ) @endcode
170
171 <h4>Relayout Dependencies</h4>
172
173 Return true from this method if this control is dependent on any of its children to calculate its own size. All relayout containers that can be dependent on their
174 children for their own size need to return true from this.
175 @code virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS ) @endcode
176
177 This will be called by children when they are using the ResizePolicy::FILL_TO_PARENT resize policy. It is the parent's responsibility to calculate the child's correct size.
178 @code virtual float CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension ) @endcode
179
180 <h4>Events</h4>
181
182 OnSetResizePolicy is called when the resize policy is set on an actor. Allows deriving actors to respond to changes in resize policy.
183 @code virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ) @endcode
184
185 <h2 class="pg">Creating a Control: TableView</h2>
186
187 This section demonstrates how size negotiation may be used when creating a table view.
188
189 First we define some policies for how table row and columns may resize. These are:
190 - Fixed: Use a fixed size
191 - Relative: Use a ratio size of empty remaining space
192 - Fill: Fill up to all remaining space, distributing evenly between all "fill" row or columns
193
194 A data structure is defined to hold information for each row and column regarding their cell size policy and their assigned and calculated sizes.
195
196 We need to be able to calculate the fixed sizes of all actors placed into table cells. The place to do this is in OnCalculateRelayoutSize. When
197 this is called every actor the table view is dependent on has already had their sizes calculated. Calculations can be made that the main calculation
198 for the actor can then use.
199 @code
200 void TableView::OnCalculateRelayoutSize( Dimension::Type dimension )
201 ...
202 CalculateRowColumnData();
203
204 if( dimension & Dimension::WIDTH )
205 {
206   CalculateFixedSizes( mColumnData, Dimension::WIDTH );
207   mFixedTotals.width = CalculateTotalFixedSize( mColumnData );
208 }
209
210 if( dimension & Dimension::HEIGHT )
211 {
212   CalculateFixedSizes( mRowData, Dimension::HEIGHT );
213   mFixedTotals.height = CalculateTotalFixedSize( mRowData );
214 }
215 ...
216 @endcode
217
218 An important override is GetNaturalSize. This will simply return the total sum of the fixed cells for each row and column.
219 @code
220 Vector3 TableView::GetNaturalSize()
221 ...
222 return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
223 ...
224 @endcode
225
226 When the time comes to calculate the size of each child in the table cells the following method will be called.
227 @code
228 float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
229 ...
230 // Use cell data to calculate child size
231 @endcode
232
233 The table view is dependent on its children if its size policy is set to USE_NATURAL_SIZE or a row or column is set to "fit" an actor.
234 The following code shows calling the base class RelayoutDependentOnChildren to check the resize policy and then searches for fit row or columns.
235 @code
236 bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension )
237 {
238   if ( Control::RelayoutDependentOnChildren( dimension ) )
239   {
240     return true;
241   }
242
243   return FindFit( mRowData ) || FindFit( mColumnData );
244 }
245 @endcode
246
247 With the cell sizes already calculated, the job of OnRelayout is to position all the actors in the table view in their respective positions.
248 @code
249 void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
250 ...
251 // Find each actor and position it, taking padding into account
252 @endcode
253
254 *
255 */