.. _pages/ui_layouting#layouting: Layouting ********* .. _pages/ui_layouting#introduction: Introduction ============ A Layout manager defines the strategy of how to position the child widgets of a parent widget. They compute the position and size of each child by taking the size hints and layout properties of the children and the size hint of the parent into account. Whenever the size of one widget changes, the layout engine will ask the layout manager of each affected widget to recompute its children's positions and sizes. Layout managers are only visible through the effects they have on the widgets they are responsible for. It is possible to place and size all children directly to static positions using `setUserBounds `_ as well, but this is quite uncommon and only used in very special cases. It is almost always better to position children using a layout manager. The layout manager can be configured on any widget, but most classes only have the protected methods to control the layout. In fact it doesn't make sense to control the layout manager of a ``Spinner``, ``ComboBox``, etc. from outside. So this scenario is quite common. Some widgets however publish the layout API. One of them is the above mentioned :doc:`/pages/widget/composite` widget. It exposes the layout system and the whole children API. The nature of layout managers is that each one has specialized options for its children. For example, one layout allows specifying a left position of a child in the canvas while another one works with rows and cells instead. Given this fact, the best place to handle these options is the layout itself. Every ``LayoutItem`` has the methods `setLayoutProperties `_ and `getLayoutProperties `_. Through this API the layout properties can be configured independendly from the layout. The validation of properties is lazy (compared to the classic qooxdoo properties). At the moment where a child with layout properties is inserted into a parent widget with a layout, these properties are checked against the rules of the layout. This validation is not possible earlier, e.g. at the definition of the *wrong* property, as at this moment the child may not have a parent yet. To make layout properties available in a convenient fashion each `add() `_ has an optional second parameter: A map with all layout properties to configure. A basic example: :: var canvas = new qx.ui.container.Composite(new qx.ui.layout.Canvas); canvas.add(new qx.ui.form.Button("Say Hello"), { left : 20, top: 20 }); This example places a button at the position 20x20 of the composite created. As you can see, the ``Composite`` widget has a convenient way -- using the constructor -- to define the layout it uses. .. _pages/ui_layouting#panes: Panes ===== Some widgets extend the ``Composite`` widget above. Typical examples here are: * `TabView Page `_ * `Popup `_ These have the same API like the composite. A slightly other type are so-called composite-like widgets. These widgets offer the same type of children management and layout management to the outside, but they redirect these properties to an inner pane. Typical widgets in this category are: * `Window `_ * `GroupBox `_ .. _pages/ui_layouting#sensible_defaults: Sensible defaults ================= By default, widgets are intelligently auto-sized. This means that most of the time you can create a widget and it will look nice. If you need greater control, you can override the defaults. Every property defined initially is also reconfigurable during the runtime of an application. When using layout managers any computed sizes are automatically refreshed and the arrangement of children is updated. Every automatically detected size can be overridden. Common settings of a widget (or spacers) are configured through the widget itself. This for example includes properties like `width `_ or `height `_. All these sizes are pixel values. Percent and other complex values are only supported by a few layout managers so these are implemented as layout properties (explained in detail later). Automatic size detection means, that limits are detected as well. Any widget in qooxdoo knows how much it can shrink and how much it can grow without interfering the functionality. The application developer can override these min/max sizes as well. This is no problem as long as the new value is tougher than the automatically detected values (e.g. lower limit of maximum width). When overriding the automatic sizes to reduce the limits layout problems may occur. It is highly suggested to keep an eye on this to omit such scenarios. One thing to keep in mind is that the ``width`` cannot override the ``minWidth`` or the ``maxWidth``. Limitation properties may be overridden by the property itself, but not by the normal size property. The ``minWidth`` can override the minimal automatically detected size, but the ``width`` cannot. This decision makes the layout system more stable as unintended overrides of the limitations are omitted in most cases. Often ``width`` and ``height`` are described as preferred sizes as the given size may not have an influence on the actual rendered size of the widget. Even if the ``width`` is configured by the user, this does not mean that the widget always get the desired width. .. _pages/ui_layouting#growing_&_shrinking: Growing & Shrinking =================== Dynamic GUIs often must work equally well in cases where not enough (or too much) room is available to render the GUI in the way meant by the developer. This may include simple cases where the size of tabs is reduced in order to handle the display of all open tabs without scrolling. More advanced cases are text which wraps to multiple lines depending on the available width (and this way influences the position of following children). In the first case we often see that an application reduces the size of the label and uses an ellipsis symbol to show that the label was too long. This feature is built-in into both commonly used widgets: `Label `_ and `Atom `_. When the underlaying layout ask to reduce the width (or the developer using the ``width`` property) the widget tries to solve the requirement dynamically. This certainly works for the height as well. :: var label = new qx.ui.basic.Label().set({ value: "A long label text which has not enough room.", width: 60 }); The second case is handled by the `height for width `_ support. Longly name but basically a really strong feature which is required quite often. It means that the height may depend on the actual width available. This especially makes sense for multi-line text where the wrapping may be influenced by the available width. The `Label `_ widget includes support for this feature when using the `rich `_ output mode (HTML content). :: var label = new qx.ui.basic.Label().set({ value: "A long label text with auto-wrapping. This also may contain rich HTML markup.", rich : true, width: 120 }); Finally this means that every widget can grow and shrink depending on the limitations given for the respective axis. Two easy accessors which disable growing or shrinking respectively are `allowGrowX `_ and `allowShrinkX `_. When the growing is disabled the configured or automatically detected maximum size is ignored and configured to the preferred size. When the shrinking is disabled the configured or automatically detected minimum size is ignored and configured to the preferred size. Two convenient methods to controlling these features without knowing of the exact dimensions. .. _pages/ui_layouting#overflow_handling: Overflow Handling ================= This leads to the next question: how to handle scenarios where the content needs more room than provided by the parent but should not shrink. This is a common case for data widgets like `Lists `_ or `Trees `_. Both extend the `AbstractScrollArea `_ to provide scrollbars to handle overflowing content. The ``ScrollArea`` itself renders scrollbars in a custom way. It does not use the native scrollbars nor the native overflowing capabilities of the browser. Benefits of this decision are: * Scroll bars can be themed. * Optimal integration into layout system. * Own implementation overrides browser quirks The scrollbars are `controlable in a way that is comparable to CSS `_. It is possible to have both scrollbars marked as ``auto`` to automatically detect the needs of the content. Or any other combination where a scrollbar may be statically hidden or visible. Each bar can be controlled separately. It is possible to enable one scrollbar statically and make the other one auto-displayed and vice-versa. :: var big = new qx.ui.form.TextArea; big.setWidth(600); big.setHeight(600); var area = new qx.ui.container.Scroll; area.setWidth(200); area.setHeight(200); area.add(big); The ``ScrollArea`` provides all typically needed methods like `scrollToX `_ to scroll to an absolute position or `scrollByX `_ to scroll by the given amount. The widget also supports the scrolling of any child into the viewport. This feature is provided through the method `scrollItemIntoView `_. It just needs any child of the widget (at any depth). :: var list = new qx.ui.form.List(); var item; for (var i=0; i<20; i++) { item = new qx.ui.form.ListItem("Item #" + i); list.add(item); if (i == 12) { list.select(item); } } One really interesting aspect of these scrolling features is, that they work all the time, even if the widget is not yet rendered. It is possible to scroll any ``ScrollArea`` before even rendered. It is even possible to scroll any child into view without the whole parent being visible. This is quite useful for selection handling (selected items should be visible). Selections of a list for example can be modified during the normal application runtime and are automatically applied and scrolled correctly after the first appearance on the screen. .. _pages/ui_layouting#layout_properties: Layout Properties ================= While there are a few core layout features which are normally respected by most layouts like the margin and alignment properties (have a look to the `LayoutItem `_ for these), there are layout specific properties which only makes sense in conjunction with the specified layout as well. These properties are called layout properties in qooxdoo. These properties are normally defined with the addition to the parent widget. The `children handling `_ normally allows a second optional parameter ``options``. The layout properties are given through a simple map e.g. :: parent.add(child, {left:20, top: 100}); This is still good readble and directly defines the properties where the children is added to the parent (and the parent's layout). While this is the common use pattern of layout properties in qooxdoo applications, it is still possible to define layout properties afterwards using `setLayoutProperties `_. The first parameter is like the second parameter in ``add`` and accepts a map of layout properties. .. _pages/ui_layouting#units_of_layout_properties: Units of Layout Properties ========================== .. _pages/ui_layouting#pixel: Pixel ----- Usually all position and size values are defined as pixel values. For example the ``left`` and ``top`` layout properties of the ``Basic`` layout are defined as pixel values. .. _pages/ui_layouting#flex: Flex ---- The flex value indicates the flexibility of the item, which implies how an item's container distributes remaining empty space among its children. Flexible elements grow and shrink to fit their given space. Elements with larger flex values will be sized larger than elements with lower flex values, at the ratio determined by the two elements. The actual flex value is not relevant unless there are other flexible elements within the same container. Once the default sizes of elements in a box are calculated, the remaining space in the box is divided among the flexible elements, according to their flex ratios. Specifying a flex value of ``0`` has the same effect as leaving the flex attribute out entirely. The easiest use case is to make exactly one child consuming the remaining space. This is often seen in modern application. For example the location field in common browsers are automatically configured to behave like this. To do this add a flex value of ``1`` to the child. In order to make more children behave like this, one could make them flexible the same way. The available space is automatically allocated between all of them. As ``flex`` allows integer values it is also possible to define weighted values. A flex value of ``2`` means double importance over ``1``. The result is that from 100 pixel remaining space and two flexible children the one with ``2`` gets about 66 pixel and the other one 33 pixel. Please note that in shrinking mode flex has an analogous effect. As a flex value of ``2`` means doubled importance compared to ``1`` the child with ``2`` is shrunken less than the child with ``1``. In contrast to qooxdoo 0.7 ``flex`` values are supplemental to the normal size values of a widget. First all children are positioned using their regular size hints. If after this step the combined size of the children is larger or smaller than the available size the ``flex`` value defines by how much each widget is stretched or shrunken. The ``flex`` property is supported by both `Box Layouts `_, the `Dock `_ Layout and the `Grid `_ (for columns and rows). In some way the `SplitPane `_ supports flex as well, but it behaves a bit different there as it is regarded as an alternative to the preferred size. .. _pages/ui_layouting#percent: Percent ------- With the above mentioned ``flex`` feature the use of percents is quite uncommon in most qooxdoo applications. Still, there are some cases where it might be interesting to define percent locations or dimensions. The `Canvas `_ Layout for example allows a child's position to contain a percent value (e.g. the layout property ``left`` could be configured to ``20%``). When there are 1000 pixel available the so-configured child is placed at a left coordinate of 200 pixel. The final coordinate is automatically updated when the outer dimensions are modified. The `LayoutItem `_'s dimension properties only support integer values. To use percentage dimensions some qooxdoo layout managers allow to define width and height using layout properties. This dimensions are then *higher* prioritized than the width and height configured in the child using the *normal* properties. The limitations defined through ``minWidth`` etc. are still respected by the layout manager. Percentage dimensions are useful to allocate a specific part of the available space to a given widget without being dependent on the configuration of the other children. It is possible to combine ``flex`` with percent dimensions. This is good because it allows to define *approximations* like ``3`` times ``33%`` instead of being forced to fill the ``100%`` completely. With flex enabled the layout manager automatically arranges the children to fill the remaining pixels. The effects of percentage dimensions in box layouts are comparable to the result of flex in a `SplitPane `_. The resulting size is computed from the available space less all statically configured gaps like spacings or margins. Layout managers with support for percentage dimensions are the already mentioned `Box `_ Layouts, but also the `Canvas `_ Layout as well as the `Dock `_ Layout. .. _pages/ui_layouting#pre-configured_widgets: Pre-configured Widgets ====================== There are a few containers in qooxdoo which use a predefined immutable layout for rendering their children. Currently these containers are included: * :doc:`/pages/widget/scroll`: Provides auto-matic scrollbars for larger content. Does not influence the size of the content which is rendered at the preferred size. Allows scrolling of the content. Supports advanced features like offset calculation and scroll into view. * :doc:`/pages/widget/stack`: Scales every widget to the available space and put one over another. Allows selection of which child should be visible. Used internally by TabView etc. * :doc:`/pages/widget/slidebar`: Comparable to the Scroll Container but only provides automatic forward and backward arrows. Supports only one axis per instance: horizontal or vertical. Buttons are automatically displayed as needed. Supports automatic shrinking of the children (other than the Scroll Container). * :doc:`/pages/widget/splitpane`: Divides the available space into two areas and provides a possibility to resize the panes for the user. Automatically respects the limitations of each child. .. _pages/ui_layouting#visibility_handling: Visibility Handling =================== Every widget can be hidden and shown at any time during the application runtime. In qooxdoo each widget's visibility might have three values: ``visible``, ``hidden`` or ``excluded``. While ``hidden`` and ``excluded`` both makes a widget invisible there is still a difference: ``excluded`` ignores the widget in during the layout process while ``hidden`` simply hides the widget and keeps the room for the widget during the layout process. The ``visibility`` property is not commonly used in qooxdoo applications.There are a few nice accessor methods for each widget: * To check the status of a widget: ``isVisible()``, ``isHidden()`` and ``isExcluded()`` * To modify the visibility: ``show()``, ``hide()`` and ``exclude()`` Please note that for performance reasons invisible widgets are not rendered or updated to the DOM which means that especially initially invisible parts could improve the startup of a qooxdoo application e.g. alternate Tab Pages, closed Window instances, Menus, etc. To work with multiple layers like in a Tab View it is suggested to use a Stack Container instead of doing the visibility management on the own.