Using Advanced Features > Defining a New Type of Layout
 
Defining a New Type of Layout
If the layout algorithms provided in Rogue Wave® Views do not meet your needs, you can develop your own layout algorithms by subclassing IlvGraphLayout.
When a subclass of IlvGraphLayout is created, it automatically fits into the generic layout framework of Rogue Wave Views and benefits from its infrastructure: generic parameters, notification of progress, and the capability to lay out any graph object using the generic graph model.
Sample Code
To illustrate the basic ideas for defining a new layout, the following simple example shows a possible implementation of the simplest layout algorithm, the Random Layout. The new layout class is called MyRandomLayout.
The following shows the skeleton of the class:
class MyRandomLayout
: public IlvGraphLayout
{
public:
MyRandomLayout()
{
}
protected:
void layout();
};
 
 
The constructor is empty. Then, the abstract method layout() of the superclass is implemented as follows:
void
MyRandomLayout::layout()
{
// obtain the graph model
IlvGraphModel* graphModel = getGraphModel();
 
// obtain the layout report
IlvGraphLayoutReport* layoutReport = getLayoutReport();
 
IlBoolean atLeastOneNodeMoved = IlFalse;
 
// obtain the layout region
IlvRect rect;
getLayoutRegion(rect);
IlvPos xMin = rect.x();
IlvPos yMin = rect.y();
IlvPos xMax = rect.right();
IlvPos yMax = rect.bottom();
 
// initialize the random generator
IlvRandom* random = (isUseSeedValueForRandomGenerator()) ?
new IlvRandom(getSeedValueForRandomGenerator()) :
new IlvRandom();
 
// get the objects in the grapher
IlList* nodes = graphModel->getNodes();
 
// browse the objects in the grapher
IlLink* l = nodes->getFirst();
while (l) {
IlAny node = l->getValue();
l = l->getNext();
 
// skip fixed nodes
if (isPreserveFixedNodes() && isFixed(node))
continue;
 
// compute coordinates
IlvPos x = xMin + (IlvPos)((xMax - xMin) * random->nextFloat());
IlvPos y = yMin + (IlvPos)((yMax - yMin) * random->nextFloat());
 
// move the node to the computed position
graphModel->moveNode(node, x, y, IlFalse);
atLeastOneNodeMoved = IlTrue;
 
// notify listeners on layout events
layoutStepPerformed();
}
delete random;
 
// set the layout report code
if (atLeastOneNodeMoved)
layoutReport->setCode(IlvLayoutReportLayoutDone);
else
layoutReport->setCode(IlvLayoutReportNoMoveableNode);
}
 
 
Note that the layout() method is protected, which is the access type of the method in the base class. This will not prevent a user outside the module that contains the class from performing the layout, because it is started using the public method performLayout.
Steps for Implementing the Layout Method
In our example, the layout method is implemented using the following main steps:
1. Obtain the graph model (getGraphModel() on the layout instance).
IlvGraphModel* graphModel = getGraphModel();
 
2. Obtain the instance of the layout report that is automatically created when the performLayout method from the superclass is called (getLayoutReport() on the layout instance).
IlvGraphLayoutReport* layoutReport = getLayoutReport();
 
3. Obtain the layout region parameter (getLayoutRegion() on the layout instance) to compute the area where the nodes will be placed.
IlvRect rect;
getLayoutRegion(rect);
 
4. Initialize the random generator. (For information on the seed value parameter, see the Random Generator Seed Value.)
IlvRandom* random = (isUseSeedValueForRandomGenerator()) ?
new IlvRandom(getSeedValueForRandomGenerator()) :
new IlvRandom();
 
5. Get a list of the nodes (getNodes() on the graph model instance).
IlList* nodes = graphModel->getNodes();
 
6. Browse the nodes, skipping fixed nodes (isFixed(node) on the layout instance) if asked by the user (isPreserveFixedNodes() on the layout instance).
// browse the objects in the grapher
IlLink* l = nodes->getFirst();
while (l) {
IlAny node = l->getValue();
// ...
 
7. Move each node to the newly computed coordinates inside the layout region (graphModel.moveNode).
graphModel->moveNode(node, x, y, IlFalse);
atLeastOneNodeMoved = IlTrue;
 
8. Notify the listeners on layout events that a new node was positioned (layoutStepPerformed() on the layout instance). This allows the user to implement, for example, a progress bar if a layout event listener was registered on the layout instance.
layoutStepPerformed();
 
9. Finally, set the appropriate code in the layout report.
if (atLeastOneNodeMoved)
layoutReport->setCode(IlvLayoutReportLayoutDone);
else
layoutReport->setCode(IlvLayoutReportNoMoveableNode);
 
Of course, depending on the characteristics of the layout algorithm, some of these steps may be different or unnecessary, or other steps may be needed.

Version 5.5.1
Copyright © 2012, Rogue Wave Software, Inc. All Rights Reserved.