...
We will now start filling in the synthesis skeleton, so open the TuringMachineDiagramSynthesis
class:
Code Block | ||||
---|---|---|---|---|
| ||||
/* Package and import statements... */ class TuringMachineDiagramSynthesis extends AbstractDiagramSynthesis<TuringMachine> { @Inject extension KNodeExtensions @Inject extension KEdgeExtensions @Inject extension KPortExtensions @Inject extension KLabelExtensions @Inject extension KRenderingExtensions @Inject extension KContainerRenderingExtensions @Inject extension KPolylineExtensions @Inject extension KColorExtensions extension KRenderingFactory = KRenderingFactory.eINSTANCE override KNode transform(TuringMachine model) { val root = model.createNode().associateWith(model); // Your dsl element <-> diagram figure mapping goes here!! return root; } } |
...
Add a new method to your synthesis that transforms a
State
into a correspondingKNode
:Code Block language javascala linenumbers true private def KNode transform(State state) { val stateNode = state.createNode().associateWith(state); return stateNode; }
While this method does indeed create a node for the state passed to it, KLighD wouldn't know how to render it yet. Let's draw the node as a rounded rectangle by adding the following line before the
return
statement:Code Block language java linenumbers true stateNode.addRoundedRectangle(4, 4, 2);
The only thing missing now is a label with the state's name:
Code Block language java linenumbers true stateNode.addInsideCenteredNodeLabel(state.name, KlighdConstants.DEFAULT_FONT_SIZE, KlighdConstants.DEFAULT_FONT_NAME); stateNode.addLayoutParam( LayoutOptions.SIZE_CONSTRAINT, EnumSet.of(SizeConstraint.MINIMUM_SIZE, SizeConstraint.NODE_LABELS));
...
That's quite nice already, but we have no way to determine which of these states is the default. Let's add a hideously ugly background colour to initial states by changing the line that adds a rounded rectangle:
Code Block | ||||
---|---|---|---|---|
| ||||
stateNode.addRoundedRectangle(4, 4, 2) => [ rect | if (state.initial) { rect.setBackgroundColor(210, 130, 210); } ]; |
...
Add the following code right before the
return
statement in the state transformation method:Code Block language javascala linenumbers true stateNode.outgoingEdges.addAll(state.outgoingTransitions.map[ t | transform(t) ])
Of course, we will have to add a
transform
method for transitions now:Code Block language scala linenumbers true private def KEdge transform(Transition trans) { val transEdge = trans.createEdge().associateWith(trans) return transEdge; }
Again, we need to tell KLighD how to render the label:
Code Block language java linenumbers true transEdge.addPolyline(2).addHeadArrowDecorator();
And the edge also needs a label that describes the transition:
Code Block language javascala linenumbers true // Add a label to the edge val label = KimlUtil.createInitializedLabel(transEdge); val labelText = trans.trigger + " / " + trans.action + " " + trans.direction + " " + trans.newChar; label.configureCenterEdgeLabel(labelText, KlighdConstants.DEFAULT_FONT_SIZE, KlighdConstants.DEFAULT_FONT_NAME);
What is missing now is to set the edge target to the node that represents the target state. There's a problem here, though: we don't even know if the target state already had a node created for it. Thus, we need to make sure it has:
Code Block language java linenumbers true transEdge.target = transform(trans.targetState);
This, however, results in a different problem: if the target state already had a node created for it, we now create another node. What we would need the state transformation method to do would be to first check if a node has already been created for a given state, and, if so, return that instead of creating a new one. It turns out that Xtend already supports this pattern. Change the method's declaration and its first line to the following:
Code Block language javascala linenumbers true private def create stateNode : state.createNode() transform(State state) { stateNode.associateWith(state);
Also, remove the return statement. Xtend now checks if we already created a node for the given state and, if not, execute the code in the method.
...