1 /*! \page size-negotiation Size Negotiation
3 <h2 class="pg">Overview</h2>
5 Size negotiation, also known as layout management, is responsible for allocating sizes to all actors on the stage based on rules of dependency between
6 the actors. Requests for relayout on actors are collected during the frame with the actual relayout performed at the end of the frame.
8 This document details how to use the size negotiation API and is intended for application writters.
10 The topics covered are:
16 <h2 class="pg">Dimensions</h2>
18 The notion of width and height is generalised into the concept of a Dimension. Several methods take a Dimension parameter.
20 The Dimension enum specifies the available dimensions as bitfields:
24 If a method can process width and height at the same time then the Dimension::ALL_DIMENSIONS mask can be specified.
26 <h2 class="pg">Resize Policies</h2>
29 The ResizePolicy enum specifies a range of options for controlling the way actors resize. These are powerful rules that enable much automatic
30 resizing behaviour. They are as following:
32 - ResizePolicy::FIXED: This is the option to use when you want the specific definite size as set by SetSize (This is the default for all actors)
33 - ResizePolicy::USE_NATURAL_SIZE: Use this option for objects such as images or text to get their natural size e.g. The dimensions of the image, or the size of the text without wrapping. Also use this on TableViews when the size of the table is dependent on its children.
34 - ResizePolicy::FILL_TO_PARENT: Size will fill up to the size of its parent's size, taking a size factor into account to allow proportionate filling
35 - ResizePolicy::SIZE_RELATIVE_TO_PARENT: Fill up the parent with a relative scale. Use SetSizeModeFactor to specify the ratio to fill up to the parent.
36 - ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT: Fill up the parent and add a fixed offset using SetSizeModeFactor.
37 - ResizePolicy::FIT_TO_CHILDREN: Size will scale around the size of the actor's children. E.g. A popup's height may resize itself around it's contents.
38 - ResizePolicy::DIMENSION_DEPENDENCY: This covers rules such as width-for-height and height-for-width. You specify that one dimension depends on another.
40 \image html size-negotiation/ResizePolicies.png
42 <h2 class="pg">Actor</h2>
44 This section details how an actor may be used with size negotiation.
46 <h3>Enabling Size Negotiation</h3>
48 Text and image actors have relayout enabled by default, while a plain Actor is disabled unless a call to SetResizePolicy is made.
50 <h3>Specifying Size Policies</h3>
52 Actors have different size policies by default. For example ImageView is set to USE_NATURAL_SIZE. This ensures that when an image actor is
53 placed on the stage it will use its natural size by default. However if the user calls SetSize with non-zero sizes on the image actor then the current
54 size policy is overridden by the FIXED size policy and the actor will take on the size specified.
56 The next step is to specify how an actor will be size negotiated. The resize policies for an actor may be specified by the following method:
57 @code void SetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ) @endcode
58 It is common to specifiy different policies for the different dimensions of width and height to achive different layouts. Different actors have
59 different resize policies specified by default. For example ImageViews are set to use USE_NATURAL_SIZE.
61 The following example code snippet shows rootActor having its width policy set to ResizePolicy::FILL_TO_PARENT and its height policy set to ResizePolicy::FIT_TO_CHILDREN.
62 It has an ImageView added to it with an explicit call to USE_NATURAL_SIZE in both dimensions called on it. This will make an actor that will
63 fill up the space of its parent in the width dimension and fit to its child in the height dimension. As the image actor child is using natural size
64 the height of the root actor will fit to the height of the child image.
67 Actor rootActor = Actor::New();
68 rootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
69 rootActor.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
70 Toolkit::ImageView image = Toolkit::ImageView::New( MY_IMAGE_PATH );
71 image.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
72 rootActor.Add( image );
75 The following images show the before and after layouts for this code example.
78 \image html size-negotiation/SizeNegotiationExample_Before.png
80 \image html size-negotiation/SizeNegotiationExample_After.png
82 This example shows an actor rootActor set to expand to its parent's width and contract/expand around its child's height. The child image actor
83 is set to natural size which means it will display at the acutal size of the image.
85 To specify that a dimension has a dependency on another dimension use ResizePolicy::DIMENSION_DEPENDENCY. For example if dimension is Dimension::HEIGHT and dependency is
86 Dimension::WIDTH then there is a height-for-width dependency in effect. The classic use case for this
87 is a text view that wraps its text. The following example snippet shows a text view that expands its width to the size of its parent, wraps its
88 contents and then determines its height based on the width.
90 TextLabel text = TextLabel::New( "Example" );
91 text.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
92 text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
95 <h3>Specifying Sizes and Size Limits</h3>
97 When wanting a specific fixed size for an actor then specify the resize policy to be FIXED and set the desired, or preferred size using SetSize.
98 If only one dimension is FIXED then the other value in the size parameter will be ignored, so it is safe to set it to zero.
100 To constrain the final negotiated size of an actor, set the following for minimum and maximum sizes respectively.
102 void SetMinimumSize( const Vector2& size )
103 void SetMaximumSize( const Vector2& size )
106 <h3>Altering Negotiated Size</h3>
108 When an actor is required to maintain the aspect ratio of its natural size the following method can be used. This is useful for size negotiating images
109 to ensure they maintain their aspect ratio while still fitting within the bounds they have been allocated. This can be one of SizeScalePolicy::USE_SIZE_SET, SizeScalePolicy::FIT_WITH_ASPECT_RATIO
110 or SizeScalePolicy::FILL_WITH_ASPECT_RATIO. The first is the default. The second will fit the actor within the bounds it has been allocated while maintaining aspect ratio. The
111 third will fill all available space, potentially overflowing its bounds, while maintaining apsect ratio.
112 @code void SetSizeScalePolicy( SizeScalePolicy::Type policy ) @endcode
114 <h3>Using Actors in Containers</h3>
116 When laying out actors in containers such as TableView it is useful to be able to specify padding that surrounds the actor. E.g. You may
117 want some white space around an image actor placed in a table cell. The padding specifies the left, right, bottom and top padding values.
118 @code void SetPadding( const Padding& padding ) @endcode
120 <h2 class="pg">An Example</h2>
122 This section shows a more complex example of how to configure size negotiation. It creates a popup and adds a table view to it with a text view,
123 an image and a sub-table. The sub-table contains a checkbox and another text view.
125 mPopup = CreatePopup();
126 mPopup.SetTitle( "Warning" );
129 Toolkit::TableView content = Toolkit::TableView::New( 2, 2 );
130 content.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
131 content.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
132 content.SetFitHeight( 0 );
133 content.SetFitHeight( 1 );
134 content.SetPadding( Padding( 20.0f, 20.0f, 20.0f, 0.0f ) );
137 Toolkit::TextLabel text = Toolkit::TextLabel::New( "Do you really want to quit?" );
138 text.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
139 text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
141 content.AddChild( text, Toolkit::TableView::CellPosition( 0, 0 ) );
144 Toolkit::ImageView image = Toolkit::ImageView::New( IMAGE_PATH );
145 image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
146 image.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
147 image.SetPadding( Padding( 20.0f, 0.0f, 0.0f, 0.0f ) );
148 content.AddChild( image, Toolkit::TableView::CellPosition( 0, 1 ) );
151 Toolkit::TableView root = Toolkit::TableView::New( 1, 2 );
152 root.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
153 root.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
154 root.SetFitHeight( 0 );
155 root.SetFitWidth( 0 );
156 root.SetPadding( Padding( 0.0f, 0.0f, 0.0f, 20.0f ) );
158 Dali::Image unchecked = Dali::ResourceImage::New( CHECKBOX_UNCHECKED_IMAGE );
159 Dali::Image checked = Dali::ResourceImage::New( CHECKBOX_CHECKED_IMAGE );
160 Toolkit::CheckBoxButton checkBox = Toolkit::CheckBoxButton::New();
161 checkBox.SetBackgroundImage( unchecked );
162 checkBox.SetSelectedImage( checked );
163 checkBox.SetSize( Vector2( 48, 48 ) );
165 root.AddChild( checkBox, Toolkit::TableView::CellPosition( 0, 0 ) );
167 Toolkit::TextLabel text2 = Toolkit::TextLabel::New( "Don't show again" );
168 text2.SetPadding( Padding( 20.0f, 0.0f, 0.0f, 10.0f ) );
170 root.AddChild( text2, Toolkit::TableView::CellPosition( 0, 1 ) );
172 content.AddChild( root, Toolkit::TableView::CellPosition( 1, 0, 0, 2 ) ); // Column span 2
174 mPopup.Add( content );
177 The resulting popup with additional buttons added is shown below.
178 \image html size-negotiation/Popup.png
180 The key things to pick out from this example are the use of the size negotiation API.
181 The content table view is set to ResizePolicy::FILL_TO_PARENT for its width and USE_NATURAL_SIZE for its height. This will result
182 in the table view expanding its width to fit the available space in the popup while also expanding/contracting its
183 height based on the size of the contents in its cells.
185 content.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
186 content.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
188 To add a little space around the left, right and bottom of the table view, some padding is added.
190 content.SetPadding( Padding( 20.0f, 20.0f, 20.0f, 0.0f ) );
192 The first text view has its width set to ResizePolicy::FILL_TO_PARENT and its height has a dimension dependency on its width. This
193 will result in a text view that fills up its width to available space in the table cell and then then calculates its
194 height based on its new width. The table view will then fit its height taking the height of the text view into account.
196 text.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
197 text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
199 The image view performs a similar relayout. It fits its width to the size of the cell and calculates its height based on the new
200 width. Some padding is added to the left of it as well to center it more.
202 image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
203 image.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
204 image.SetPadding( Padding( 20.0f, 0.0f, 0.0f, 0.0f ) );
206 The sub table view is similar as well in that it expands its width to the size of its cell. When it is added to the table view it
207 will span two columns. Its height is set to natural size so that it will grow or shrink based on its children cells. Note that for
208 a container like table view, USE_NATURAL_SIZE acts in a similar manner to ResizePolicy::FIT_TO_CHILDREN in that the size of the container could
209 grow or shrink based on the sizes of the child actors.
211 root.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
212 root.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
214 The checkbox is set to have a fixed size.
216 checkBox.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
218 The second text view has not specified a resize policy so will use its default of USE_NATURAL_SIZE.
220 <h2 class="pg">Debugging</h2>
222 When constructing large scenes using interacting resize policies it is useful to be able to debug the relayout process. The following sections
223 describe a pitfall to avoid when creating scenes and a way to print debug output about the actors.
225 <h3>Infinite Dependency Loops</h3>
226 Despite the power of the resize rules there is one pitfall to be aware of: infinite dependency loops. The most simplest form of this is
227 shown by a parent actor with resize policy set to ResizePolicy::FIT_TO_CHILDREN with a child that has a resize policy of ResizePolicy::FILL_TO_PARENT. Who should
228 determine the size in this case? A more complex loop occurs when ResizePolicy::DIMENSION_DEPENDENCY comes into play. Say a parent has a width policy
229 of ResizePolicy::DIMENSION_DEPENDENCY with height and a height policy of ResizePolicy::FIT_TO_CHILDREN. The parent has a single child with a height policy ResizePolicy::DIMENSION_DEPENDENCY
230 with width. If the child's width policy is ResizePolicy::FILL_TO_PARENT then a loop will occur. These are two simple examples but the loops could occur
231 over larger spreads of parent child relationships. These loops are detected by the relayout algorithm with the result being that actors will
232 receive zero sizes. These loops are not common but are still something to watch out for.
234 <h3 class="pg">Inspecting Actor Relayout Properties</h3>
235 To get a print out of the stage hierarchy before and after negotiation, with a list of actors that were negotiated set the LOG_RELAYOUT_CONTROLLER environment variable to 3,true.
239 $ LOG_RELAYOUT_CONTROLLER=3,true dali-demo
241 Example output from the logging is as follows:
243 PushButton, OKAY_BUTTON - Pos: [185, 0, 0.1] Size: [165, 76, 76], Dirty: (FALSE,FALSE), Negotiated: (TRUE,TRUE), Enabled: TRUE, (0x1649850)
245 The format is as follows:
247 [Actor type], [Actor name] ? Pos:[X, Y, Z] Size[Dimension::WIDTH, Dimension::HEIGHT, DEPTH], Dirty:(Dimension::WIDTH, Dimension::HEIGHT), Negotiated: (Dimension::WIDTH, Dimension::HEIGHT), Enabled: BOOLEAN, (Object address)
248 - <i>Actor type</i>: The type name of the actor E.g. PushButton
249 - <i>Actor name</i>: The name set on the actor with SetName(). Useful for debugging.
250 - <i>Pos</i>: The position of the actor
251 - <i>Size</i>: The current size of the actor. Check this to see if the actor has been negotiated correctly.
252 - <i>Dirty</i>: Booleans to say if the width or height has been marked as dirty by the relayout dirty flag propagation algorithm
253 - <i>Negotiated</i>: Booleans to say if the width or height has been negotiated by the size negotiation algorithm
254 - <i>Enabled</i>: Boolean to say if the actor is enabled for size negotitation
255 - <i>Object address</i>: The address of the actor object in memory