-
Hi, I only found this discussion which reveals a short glimpse of possibilities. Thanks for help. |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 4 replies
-
Hi @rsoika, In the meantime I will try to give you a short summary on how to use the In GLSP we distinguish between micro and macro layout. Usually, the server is responsible for the macro layout, that is the arrangement of the main model elements (i.e. nodes and edges). In turn, the client is responsible for the micro layout, that is the positioning and size computation of elements within a container element such as nodes. (For more details see also: https://www.eclipse.org/glsp/documentation/clientlayouting/) The server just tells the client which layouter it should use and can provide additional configuration options. This information is stored in the graphical model. The Here are three built-in layout types that can be used: “hbox”,”vbox” and “freeform”. For an example let's consider the following node builder: new GNodeBuilder()
.layout("vbox")
.layoutOptions(new GLayoutOptions()
.hAlign("center"))
.add(new GLabelBuilder()
.text("label1")
.build())
.build(); This builder creates a node whose content (i.e. children) should be layouted with the The set of available default options is defined in the Unfortunately, as you already noticed, this concept is not well documented at all. Layouters may only use a subset of the available options and also the expected option value type is not documented. This information is currently scattered across GLSP client, sprotty and GLSP server code but I will try my best to give you a concise description: The following options are commonly supported by all layouters:
Vbox Layouter ("vbox")
HBox Layouter ("hbox")
Free from ("freeform") Side note on the |
Beta Was this translation helpful? Give feedback.
-
Thanks for this information - it helps a lot (Even if it will take me some time until I can safely apply this knowledge). One thing I would like to suggest in addition is to illustrate the things explained here by the Task Element in the Workflow Example 0.9.0. The Task contains a Label and an Icon. The Server part simply defines the vertical layout for the too compartments 'Icon' and 'Header'. I understand now that this is a macro layout information. The whole concept is really impressive! It seems to be very well thought out and goes much further than anything else I have seen so far. For the BPMN modeling tool I am working on this is really the best fit. |
Beta Was this translation helpful? Give feedback.
-
Sorry but I must come back to the topic. Even as you provide much information I am still not able to apply them to my different scenarios. If I want to achieve the following element layout: I try to do define a server side macro layout like this: public class EventNodeBuilder extends AbstractGNodeBuilder<EventNode, EventNodeBuilder> {
....
@Override
public void setProperties(final EventNode node) {
super.setProperties(node);
node.setName(name);
node.setNodeType(nodeType);
node.setLayout(GConstants.Layout.VBOX);
// Set min width/height
node.getLayoutOptions().put("minWidth", 40);
node.getLayoutOptions().put("minHeight", 40);
node.getLayoutOptions().put(H_ALIGN, "center");
// define icon and label
node.getChildren().add(createCompartmentIcon(node));
node.getChildren().add(createCompartmentHeader(node));
}
.....
} So I am extending the Client Now on the client side (micro layout) I define my event element in the const bpmnDiagramModule = new ContainerModule((bind, unbind, isBound, rebind) => {
....
configureModelElement(context, 'event:start', EventNode, CircularNodeView);
... and my EventNode looks like this export class EventNode extends CircularNode implements Nameable, WithEditableLabel {
static readonly DEFAULT_FEATURES = [
connectableFeature,
deletableFeature,
selectFeature,
boundsFeature,
moveFeature,
layoutContainerFeature,
fadeFeature,
hoverFeedbackFeature,
popupFeature,
nameFeature,
withEditLabelFeature
];
eventType?: string;
get editableLabel(): (SChildElement & EditableLabel) | undefined {
const label = this.children.find(element => element.type === 'label:heading');
if (label && isEditableLabel(label)) {
return label;
}
return undefined;
}
get name(): string {
const labelText = this.editableLabel?.text;
return labelText ? labelText : '<unknown>';
}
} The result will look like this: I fear this is the wrong approach to achieve the following:
So I guess that I need to define my own custom View to arrange the elements in the right order @injectable()
export class EventView extends ShapeView {
.....
...??
} puh... I am absolute unsure how to go ahead.... === |
Beta Was this translation helpful? Give feedback.
-
I figured out, that technical this is possible if I change the svg attributes with the Browser Debugger I can adjust the 'transform' attribute like
The text position changed: But can I do this from my GLSP Server code? Or my GLSP Client code? |
Beta Was this translation helpful? Give feedback.
-
I came a little bit near to a solution by defining a custom EventNodeView: @injectable()
export class EventNodeView extends ShapeView {
render(element: EventNode, context: RenderingContext): VNode | undefined {
if (!this.isVisible(element, context)) {
return undefined;
}
const vnode = (
<g transform={'scale(1) translate(74,52)'}>
<circle r="23.5" cx="23.5" cy="23.5" class-sprotty-node={true}></circle>
<text transform={'translate(15,52) translate(-40, 13)'} class-heading={true} class-sprotty-label={true}>{element.name}</text>
</g>
);
const subType = getSubType(element);
if (subType) {
setAttr(vnode, 'class', subType);
}
return vnode;
}
} The result looks like: but it's still a lot of guessing..... |
Beta Was this translation helpful? Give feedback.
-
The Final SolutionAfter all I come to the following solution - supporting also editable label headers: My ......
@Override
public void setProperties(final EventNode node) {
super.setProperties(node);
node.setName(name);
node.setNodeType(nodeType);
node.setLayout(GConstants.Layout.VBOX);
node.getLayoutOptions().put(H_ALIGN, "center");
node.getLayoutOptions().put(H_GRAB, true);
node.getLayoutOptions().put(V_GRAB, true);
node.getChildren().add(createCompartmentHeader(node));
}
private GLabel createCompartmentHeader(final EventNode taskNode) {
return new GLabelBuilder(ModelTypes.LABEL_HEADING) //
.id(taskNode.getId() + "_classname") //
.text(taskNode.getName())
.build();
} My final view implementation looks like this: @injectable()
export class EventNodeView extends ShapeView {
render(element: EventNode, context: RenderingContext): VNode | undefined {
if (!this.isVisible(element, context)) {
return undefined;
}
// first we compute the event symbol based on the event type
let eventSymbol = undefined;
if (element.type === "event:start") {
// eslint-disable-next-line max-len
eventSymbol = 'M14 7v1H8v6H7V8H1V7h6V1h1v6h6z';
} else {
// default symbol
eventSymbol = 'M7.116 8l-4.558 4.558.884.884L8 8.884l4.558 4.558.884-.884L8.884 8l4.558-4.558-.884-.884L8 7.116 3.442 2.558l-.884.884L7.116 8z';
}
// find the label:heading
let header = undefined;
for (const entry of element.children) {
if (entry instanceof SLabel && entry.type === "label:heading") {
header = entry;
// adjust allignment and position
header.alignment = { x: 0, y: 0 };
header.position = { x: 0, y: 60 };
}
}
let vnode = undefined;
if (header) {
vnode = (
// render circle with a event symbol and the label:heading
<g transform={'scale(1) translate(0,0)'}>
<circle r="20" cx="20" cy="20" class-sprotty-node={true}></circle>
<g class-icon={true}>
<path transform={'scale(2.0),translate(1.75,1.75)'}
d={eventSymbol} />
</g>
<g transform={'translate(0, 0) translate(0, 0)'}>
{context.renderElement(header)}
</g>
</g>
);
} else {
// we do not found a header so simply draw a circle...
vnode = (
<g transform={'scale(1) translate(0,0)'}>
<circle r="20" cx="20" cy="20" class-sprotty-node={true}></circle>
</g>
);
}
const subType = getSubType(element);
if (subType) {
setAttr(vnode, 'class', subType);
}
return vnode;
}
} I know that my Serverside Layout information did not make much sense as it is mostly ignored by the client implementation. But hey! I have editable labels and a symbol within my circle!!! Can you give me a short review? Maybe some of this code can become part of a documentation chapter "Draw your own element view" |
Beta Was this translation helpful? Give feedback.
-
@tortmayr can you please have a short look on my last comments. Just to ensure that I am on the right track. |
Beta Was this translation helpful? Give feedback.
The Final Solution
After all I come to the following solution - supporting also editable label headers:
My
setProperties
method in the server side event node Builder looks like this: