Objective Toolkit : Chapter 30 Introduction to Objective Toolkit for ATL : Window Layout Manager for Composite Controls
Window Layout Manager for Composite Controls
The Layout Manager classes provide child window size and position dynamics for resizable ATL composite controls, dialog boxes, and windows. You can also utilize the size constraint capabilities to limit the sizing of your control or dialog to reasonable values. Layout capabilities are expressed in the layout algorithm classes. OT/ATL provides the COtlScaleNode and COtlRelativeNode algorithm classes for this purpose. A corresponding layout node object represents each child window. The top-level window or dialog is usually represented by an algorithm node object that maintains a collection of managed child nodes, much like child window relationships. Layout management is enabled by inheriting from an algorithm class and a message listener or plug-in class. This can be done in one step with the template class COtlLayoutImpl. You need to create child nodes for the child windows that you want to manage. Typically, do this in OnInitDialog(). The COtlLayoutFactory class has convenience functions for creating child window nodes (COtlWindowNode) for all child windows or selected ranges. You can create your own layout node types derived from COtlLayoutNode. These can be algorithm nodes or simple child nodes. The following sections below explore these topics in more detail.
Layout Manager Algorithms
This section describes each of the default layout algorithms provided with the Objective Toolkit for ATL Layout Manager component. You can also create your own custom layouts that are derived from our algorithms or from the common base class COtlLayoutNode.
Scale Layout
The Scale Layout maintains all children with a constant aspect ratio to the parent scale node. In other words, the child node’s top, left, right, and bottom coordinates are stored as percentages of the parent node’s size and are resolved to actual pixel values with each recalculation. This guarantees a constant aspect ratio no matter what size the parent node is. This algorithm is implemented by COtlScaleNode.
Relative Layout
The Relative Layout allows a logical organization of layout nodes in coordinates relative to other layout nodes. Common actions here might include moving or stretching child controls in response to an overall dialog size change.
For example, you can achieve layouts such as:
“Set the left side of node 1 equal to the right side of node 2 plus 10 pixels,” or
“Set the bottom of node 1 to 25 percent of the height of node 2,” or
“Move node 1 so that its bottom is equal to the top of node 2 minus 10 pixels,” and so on.
Each of these rules is called a constraint. Constraints are objects that define units of relative layout behavior.
This algorithm is implemented by COtlRelativeNode.
Adding Layout Management to Your Applications
Choose a layout algorithm and then include the necessary header files in your dialog or window implementation class. The Layout Manager implementation class (COtlLayoutImpl) is added to your list of base classes, templatized on the algorithm chosen. Here is the scale algorithm:
 
#include <otlscalenode.h>
#include <otllayoutimpl.h>
#include <otllayoututil.h>
 
// CScaleDialog
class CScaleDialog :
public CAxDialogImpl<CScaleDialog>,
public COtlLayoutImpl<COtlScaleNode>
{
Now the Layout Manager needs to gather a list of child nodes to manage. Typically, a window layout node is created for every child window on the dialog, although this is not a requirement. We can use the OnInitDialog() message handler to create child nodes. Insert the following code after all the child windows have been created and initialized:
 
// optional: set dialog box size limits
SetMinMaxSize(150, 255, 900, 600, 0);
// helper object for enumerating child windows and building nodes
COtlLayoutFactory layoutFactory;
// makes a node for every child window
layoutFactory.AutoPopulateNodeWnd(this, m_hWnd);
// set all child nodes to use optimized redraw
// (static controls require it)
ModifyNodeStyleEx(0,OTL_LNODE_EX_OPTIMIZE_REDRAW,TRUE);
// kick off the layout process
AutoInit(this, m_hWnd);
In this case, the dialog itself serves as the parent scale node and all its child windows are managed as child COtlWindowNode objects. Some Layout Manager functions require a parent node and a window handle. This allows for flexibility in the case of nested layouts, and when the parent node is not the same as the window class. Notice that the preceding example uses a helper object, COtlLayoutFactory. This is a convenient utility class that you can use to build the layout node tree.
The only thing you need to do is let the Layout Manager look at the incoming window messages. To do this, add the following line to the dialog's message map:
 
CHAIN_MSG_MAP( COtlLayoutImpl< COtlScaleNode > )
The template parameter for COtlLayoutImpl must match the one you used for the base class. COtlLayoutImpl is a very thin convenience class that derives from your algorithm of choice and COtlLayoutPlugin, which listens for sizing messages.
Now, give your dialog a resizable border using the resource editor so scaling is applied when the dialog is resized.