When building Rich Internet Applications (RIAs) there is a greater need for control over the layout of the application user interface. The provision for a greater control is a common feature amongst RIA technologies such as Flex, Silverlight and JavaFX.
Similarly, Morfik also provides a model that allows for a greater level of control over the application user interface layout; however, unlike these platforms, Morfik does not rely on browser plug-ins or special software to achieve this. Morfik has developed a unique technique that is implemented in Ajax code, removing the need for browser plug-ins. This approach is named Plastic Layout due to its ability to combine absolute positioning with flow layout.
Plastic Layout is a technique in which the developer successively breaks the application user interface into smaller functional sections based on the application logic and the graphical design of the user interface. These sections are then programmatically organized into a spatial tree structure at run time. Each node in the tree is aware of the existence, state and behavior of other nodes and can respond to layout changes (communicated as events) according to changes in content and the rules set out by the developer at design-time.
While in Morfik the navigational structure of an application is created with Pages, the pages themselves are composed entirely of Forms. All the application user interface is thus built using forms. Forms represent major nodes within this tree structure; however, there are other nodes that exist in the tree and are important in the layout process. A form is comprised of a series of repeatable bands. Within each band there are user interface elements such as button and container controls. A special node, the SubForm Control, is used to link forms within this structure. In this documentation the term Plastic Layout Tree is used to refer to this hierarchical structure as depicted in Figure 1.
|Figure 1: Plastic Layout Tree|
All nodes within the tree have Width and Height properties. With the exception of Band nodes, all other nodes assume a location within the space provided by their respective parent nodes. The location is defined by the Left and Top properties. Bands are special nodes with unique layout characteristics. They are laid within a form in a sequence and with relative positioning.
Content-driven layout versus container-driven layout
To better understand Morfik Plastic Layout it may help to think in terms of two fundamental forces that drive the layout process. Every node within the Plastic Layout Tree is subject to these two forces. One is the force exerted by the content within a node (content-driven layout) while the other is the force exerted by the container node (parent) on the contained node (container-driven layout).
In the container-driven layout case, Figure 2, resizing of Container1 will force Container2 to move down (in this example Container2 is bottom-justified). In the content-driven layout case, Figure 3, the TextLabel control is forced by the content to grow in order to reveal the entire text content.
These two processes operate independently and in parallel with little conflict. Conflicts can only arise along the Y-axis and when such a case arises priority is given to the change initiated by the container-driven layout process'.
It is worth mentioning that content-driven layout dominates the process when building applications that have the look and feel of a website while the container-driven layout dominates when building desktop-like applications. In general, however, both these layout processes are used within most applications created by Morfik.
Grow/shrink properties (content-driven)
A change in the content of a child control will cause its parent control either to grow or shrink depending on whether the amount of content was increased or decreased. On the other hand, if the content of the parent control changes, the child control is not affected. It is important to note that a change is propagated in a cascading style from bottom to the top of the Plastic Layout Tree.
In content-driven layout a change in control content could affect sibling controls as well (controls that have been placed in the same container). Depending on whether the content is shrunk or grown, sibling controls will be either pulled up (to fill up the resultant gap) or moved down (to clear the way for control growth). The siblings that are affected are ones that fall entirely below the primary control being adjusted.
There are three control properties and four events that allow developers to fully control the behavior of the content-driven layout.
Grow/Shrink related properties:
|Can Grow||The CanGrow property determines the behavior when the Caption text is too large to fit into the Control:
|Can Shrink||The CanShrink property determines the behavior when the Caption text is too small to completely fill the Control:
|Shrink On Hide||The ShrinkOnHide property specifies how Morfik's Layout engine repositions other controls when the container's visibility is changed at runtime.|
Grow/Shrink related Events:
|On After Grow Or Shrink||This event is fired within the browser after the height of a control is adjusted in order to fit its new content.|
|On After Pushed Or Pulled||This event is fired within the browser after the position of a control has changed in response to a change in the content of a sibling control.|
|On Before Grow Or Shrink||This event is fired within the browser before the height of a control is adjusted in order to fit its new content.|
|On Before Pushed Or Pulled||This event is fired within the browser before the position of a control is changed in response to a change in the content of a sibling control.|
Placement properties (container-driven)
A change in a parent container's dimensions could affect the placement of its child controls depending on the child control's placement properties. A change in the dimension of a child control, on the other hand, will not affect its parent control's dimension. The affect of a change cascades down the Plastic Layout Tree until it reaches the bottom nodes.
|Figure 5: Placement properties|
There are two control properties that allow developers to fully control the behaviour of the container-driven layout process:
- Horizontal Placement
- Vertical Placement
Plastic Layout in action
There are practical aspects to the implementation of Plastic Layout that are important to know. The following diagram shows the flow of the Plastic Layout process at run time:
|Figure 6: Layout generation|
The first thing to note is that the Plastic Layout process does not generate the actual layout. The initial layout is created on the server-side by the form generator and then sent to the browser-side of the application for final processing. All the layout information defined at design-time is contained in an XML template which is stored inside the .MXR file. This XML template contains precise positioning information, information about formatting and data sources as well as instructions on the required plasticity of the layout. The Morfik Form Generator (on the server side) first processes this template and uses the formatting information as well as accessing the specified data sources to generate the starting HTML. It then sends it to the browser for final processing. The Plastic Layout begins in the browser by first interpreting the developer‘s instructions on plasticity and then adjusting the location and the dimensions of various nodes in the Plastic Layout Tree to bring flexibility to a layout that is otherwise rigidly defined.
The second thing to note is the nature of key events that start the layout process and the various actions taken by the Plastic Layout system in response to these events.
Opening a Form—The layout process is triggered by a number of different events. The most significant of these events occurs when a form is opened in response to a call to the OpenForm function. The event occurs just before a form is made visible in the browser. It invokes the layout process to begin its plastic work on the content of the form. There are three steps involved:
Step 1: The layout process first processes all TextLabels, CheckBoxes and Optionbuttons and depending on their CanGrow and CanShrink properties will apply height adjustments to each of these controls. Each adjustment may result in subsequent changes of the height of the parent control or a change in the location of sibling controls. The cascading nature of this process, however, is confined to those controls that are within the same form; no Event is allowed to cross the boundary of the Form into the Parent Form. Similarly, the same layout process goes through all containers within the form that have their ShrinkOnHide set to true and will perform height adjustments.
Step 2: A single grow/shrink Event is triggered on the Form’s Owner Subform which will carry through to the Owner Form the aggregate result of all the changes that were made in the Form during Step 1. The Parent Form will do all the necessary adjustments to its child controls before passing this event up the next form in the tree. This will continue until the top form in the Plastic Layout Tree is reached.
Step3: The container-driven layout process begins at this point in the cycle. It starts from the form node that is just being loaded and will recursively work down the Plastic Layout tree until the bottom most nodes of the tree are reached. All controls that have their HorizontalPlacement or VerticalPlacement properties set are processed during this step.
|Note:||When a Form is cached within a SubForm, subsequent calls to the OpenForm command on the same form will only result in Step 2 and Step 3 to be executed.|
|Note:||Opening a form often results in one or more child forms to open implicitly. These secondary forms, upon opening, will only execute Step 1 and Step 2. Step 3 is only run for the primary form being opened.|
Setting Width and Height properties—Programmatically setting the width or height of a control will trigger the container-driven and the content-driven layout processes to run. The container-driven layout process is run on all the child controls, provided that the HorizontalPlacement or VerticalPlacement properties are set. The content-driven layout is run on the control itself, provided that the control is a TextLabel, Checkbox or an OptionButton and either the CanGrow or CanShrink properties are set.
|Note:||The content-driven layout process only responds to the changes in the Width property. Setting the height property does not start the content-driven layout process.|
Care must be taken when setting the Width or Height properties of a control as the recursive nature of the layout process could result in multiple runs that may not be necessary and be waste of processor’s time.
Resizing Browser Window—This event will trigger the container-driven layout process to run on the main form of the application and will expand through the entire Plastic Layout Tree. If the properties of controls that determine the layout behavior are not set properly this is where the negative effect will be seen. The application will appear as slow in responding to the resize events that are fired repeated during the resizing of the browser window. To mitigate this effect, a timer is set up to reduce the frequency of events that are passed through to the system; however, this does not remove the need to carefully configure control layout properties within a project.
Other Actions—There are three other actions that trigger the content-driven layout process to run:
- Changing the visible property of a container (only if it actually changes)
- Changing the caption of a TextLabel, CheckBox or OptionButton (only if the value changes)
- Changing the active tab in a TabControl result in the layout process to be run on the TabSheet control being activated.
Tips, tricks and things you need to know
In order to gain maximum benefit from the Plastic Layout, it is beneficial to consider the following when designing an application:
1) Use containers to guard against the undesirable effects of ‘grow and shrink’ on sibling controls. It is not always desirable to move sibling controls that fall underneath the control that is being re-sized. Use a borderless container to isolate sibling controls that are not to be moved by the expanding or shrinking control. This technique is demonstrated in Figure 7. Note the effect of container D in isolating container B so that when the text label is grown, container B remains fixed in place.
|Figure 7: Using containers to isolate siblings|
2) Sometimes it is not possible to use a container to guard against the undesirable effects of ‘grow and shrink’ on sibling controls. In these situations use OnBeforeGrowOrShrink and OnBeforePushedOrPulled events to achieve the same result as shown in the code snippet below:
Procedure Form1.TextLabel5BeforePushedOrPulled(Var deltaY: Integer); Begin deltaY := 0; End;
3) Do not set CanGrow and CanShrink properties if not needed—there are normally many instances of TextLabel controls that are static and are not data bound. These controls usually do not require their sizes to be changed at runtime. Make sure that the CanGrow property and CanShrink properties for these controls are set to No and False, which are the default values. Otherwise the layout process attempts to adjust their size, which often results in an insignificant amount of resizing. This insignificant change in size can, however, trigger a wave of grow and shrink operations on parent nodes further up the Plastic Layout Tree. If not checked, this problem could have a very negative impact on the performance of continuous forms. You could alternatively set the InternalGrowShrinkOverride field of a control to True in order to make it invisible to the Plastic Layout process.
4) Place sibling controls with the same justification in a common container. This will reduce the number of operations performed to produce the same effect as shown in Figure 8. Note that Container A is the only control that needs to have its HorizontalPlacement property set to hpRightJustify.
|Figure 8: Optimizing alignment|
5) Do not change the design-time property values that are stored in the creation record field. The Plastic Layout process uses in its calculations the design-time values of position and size properties that are stored in the Attrs field. Changing these values could be detrimental to the Plastic Layout process.
6) The Plastic Layout process does not regard hiding a control as affecting its content. Therefore, it does not take any action when the visible property of a control is changed. For container controls, however, this behavior can be changed through the ShrinkOnhide property. The current implementation, however, simply sets the height of a container to zero when its visible flag is set to false, provided the value of ShrinkOnHide property is set to True. The problem will arise when the container is made visible again. The Plastic Layout process attempts to restore the original height of the container based on its child controls. This results in the bottom margin (the distance between the bottom of the bottom-most control and the bottom of the container) to disappear. To work around this problem a dummy control can be placed right at the bottom of the container control so as to maintain the bottom margin.
Application’s alignment within the browser window
Since the application’s main form (top node of the Plastic Layout Tree) does not have a parent container its alignment within the browser is handled in a special way. There is an application-level property, Page Alignment, that controls the alignment of application’s main form relative to the browser window. This property can be accessed through the Options|Application dialog box as shown in Figure 9.
|Figure 9: Application's page alignment property|
The possible options for page alignment are:
- Left—The application’s Main Form is placed in the top left corner of the client area of the browser window. Resizing the browser window in the horizontal or vertical directions will not affect the application’s Main Form alignment (Figure 10).
|Figure 10: Left alignment|
- Center—The application’s main form is horizontally centred within the client area of the browser window. Resizing browser window in the horizontal direction will trigger an event that will start the layout process (Figure 11).
|Figure 11: Center alignment|
- Right—The application’s Main Form is placed in the top right corner of the client area of browser window. Resizing the browser window in the horizontal direction will trigger an event that will start the layout process (Figure 12).
|Figure 12: Right alignment|
- Stretched—The application’s main form is stretched in both directions in order to fill the entire area of the client portion of the browser window. Resizing browser window in the horizontal or vertical direction will trigger an event that will start the layout process (Figure 13).
|Figure 13: Stretched alignment|
- Stretched (horizontal direction only)—The application’s Main Form is stretched in a horizontal direction in order to fill the entire width of the client portion of the browser window. Resizing the browser window in the horizontal direction will trigger an event that will start the layout process (Figure 14).
|Figure 14: Streched (horizontal direction only) alignment|
- Introduction and Overview
- How is Morfik different?
- Identifying and creating your application pages
- Building navigation menus and linking your application pages
- Getting to know Morfik Forms
- Using Forms to build your application user interface
- Working with Forms to add behavior and content to your application
- Using Controls and Widgets to add interactivity and display content
- Controlling the layout of your application
- Using Graphical Effects to enhance presentation
- Maintain consistent presentation through use of Themes and Styles
- Creating Interfaces for the Mobile Web