Search in sources :

Example 1 with KRendering

use of de.cau.cs.kieler.klighd.krendering.KRendering in project lingua-franca by lf-lang.

the class LinguaFrancaShapeExtensions method addReactorFigure.

/**
 * Creates the visual representation of a reactor node
 */
public ReactorFigureComponents addReactorFigure(KNode node, ReactorInstance reactorInstance, String text) {
    int padding = getBooleanValue(LinguaFrancaSynthesis.SHOW_HYPERLINKS) ? 8 : 6;
    Function1<KRoundedRectangle, KRendering> style = r -> {
        _kRenderingExtensions.setLineWidth(r, 1);
        _kRenderingExtensions.setForeground(r, Colors.GRAY);
        _kRenderingExtensions.setBackground(r, Colors.GRAY_95);
        return _linguaFrancaStyleExtensions.boldLineSelectionStyle(r);
    };
    KRoundedRectangle figure = _kRenderingExtensions.addRoundedRectangle(node, 8, 8, 1);
    _kContainerRenderingExtensions.setGridPlacement(figure, 1);
    style.apply(figure);
    figure.setProperty(REACTOR_CONTENT_CONTAINER, true);
    // minimal node size is necessary if no text will be added
    List<Float> minSize = List.of(2 * figure.getCornerWidth(), 2 * figure.getCornerHeight());
    _kNodeExtensions.setMinimalNodeSize(node, minSize.get(0), minSize.get(1));
    // Add parent container
    KRectangle parentContainer = _kContainerRenderingExtensions.addRectangle(figure);
    _kRenderingExtensions.setInvisible(parentContainer, true);
    setGridPlacementDataFromPointToPoint(parentContainer, LEFT, padding, 0, TOP, padding, 0, RIGHT, padding, 0, BOTTOM, _utilityExtensions.hasContent(reactorInstance) ? 4 : padding, 0);
    // Add centered child container
    KRectangle childContainer = _kContainerRenderingExtensions.addRectangle(parentContainer);
    _kRenderingExtensions.setInvisible(childContainer, true);
    _kRenderingExtensions.setPointPlacementData(childContainer, _kRenderingExtensions.LEFT, 0, 0.5f, _kRenderingExtensions.TOP, 0, 0.5f, _kRenderingExtensions.H_CENTRAL, _kRenderingExtensions.V_CENTRAL, 0, 0, 0, 0);
    KGridPlacement placement = _kContainerRenderingExtensions.setGridPlacement(childContainer, 1);
    KText childText = _kContainerRenderingExtensions.addText(childContainer, text);
    DiagramSyntheses.suppressSelectability(childText);
    _linguaFrancaStyleExtensions.underlineSelectionStyle(childText);
    if (!_utilityExtensions.isRoot(reactorInstance) && reactorInstance.getDefinition().getHost() != null) {
        KRendering cloudUploadIcon = _linguaFrancaStyleExtensions.addCloudUploadIcon(childContainer);
        setGridPlacementDataFromPointToPoint(cloudUploadIcon, LEFT, 3, 0, TOP, 0, 0, RIGHT, 0, 0, BOTTOM, 0, 0);
        placement.setNumColumns(2);
        if (getBooleanValue(LinguaFrancaSynthesis.SHOW_REACTOR_HOST)) {
            KText reactorHostText = _kContainerRenderingExtensions.addText(childContainer, _utilityExtensions.toText(reactorInstance.getDefinition().getHost()));
            DiagramSyntheses.suppressSelectability(reactorHostText);
            _linguaFrancaStyleExtensions.underlineSelectionStyle(reactorHostText);
            setGridPlacementDataFromPointToPoint(reactorHostText, LEFT, 3, 0, TOP, 0, 0, RIGHT, 0, 0, BOTTOM, 0, 0);
            placement.setNumColumns(3);
        }
    }
    if (reactorInstance.isBank()) {
        List<KRendering> bank = new ArrayList<>();
        KContainerRendering container = _kRenderingExtensions.addInvisibleContainerRendering(node);
        // TODO handle unresolved width
        KRoundedRectangle banks;
        banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
        style.apply(banks);
        setGridPlacementDataFromPointToPoint(banks, LEFT, BANK_FIGURE_X_OFFSET_SUM, 0, TOP, BANK_FIGURE_Y_OFFSET_SUM, 0, RIGHT, 0, 0, BOTTOM, 0, 0);
        if (reactorInstance.getWidth() == 3) {
            banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
            style.apply(banks);
            setGridPlacementDataFromPointToPoint(banks, LEFT, BANK_FIGURE_X_OFFSET_SUM / 2, 0, TOP, BANK_FIGURE_Y_OFFSET_SUM / 2, 0, RIGHT, BANK_FIGURE_X_OFFSET_SUM / 2, 0, BOTTOM, BANK_FIGURE_Y_OFFSET_SUM / 2, 0);
        } else if (reactorInstance.getWidth() != 2 && reactorInstance.getWidth() != 3) {
            banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
            style.apply(banks);
            setGridPlacementDataFromPointToPoint(banks, LEFT, 2 * BANK_FIGURE_X_OFFSET_SUM / 3, 0, TOP, 2 * BANK_FIGURE_Y_OFFSET_SUM / 3, 0, RIGHT, BANK_FIGURE_X_OFFSET_SUM / 3, 0, BOTTOM, BANK_FIGURE_Y_OFFSET_SUM / 3, 0);
            banks = _kContainerRenderingExtensions.addRoundedRectangle(container, 8, 8, 1);
            style.apply(banks);
            setGridPlacementDataFromPointToPoint(banks, LEFT, BANK_FIGURE_X_OFFSET_SUM / 3, 0, TOP, BANK_FIGURE_Y_OFFSET_SUM / 3, 0, RIGHT, 2 * BANK_FIGURE_X_OFFSET_SUM / 3, 0, BOTTOM, 2 * BANK_FIGURE_Y_OFFSET_SUM / 3, 0);
        }
        container.getChildren().add(figure);
        setGridPlacementDataFromPointToPoint(figure, LEFT, 0, 0, TOP, 0, 0, RIGHT, BANK_FIGURE_X_OFFSET_SUM, 0, BOTTOM, BANK_FIGURE_Y_OFFSET_SUM, 0);
        bank.addAll(container.getChildren());
        KRectangle widthLabelContainer = _kContainerRenderingExtensions.addRectangle(container);
        _kRenderingExtensions.setInvisible(widthLabelContainer, true);
        setGridPlacementDataFromPointToPoint(widthLabelContainer, LEFT, 12, 0, BOTTOM, 9, 0, RIGHT, 6, 0, BOTTOM, 0.5f, 0);
        // Handle unresolved width.
        String widthLabel = reactorInstance.getWidth() >= 0 ? Integer.toString(reactorInstance.getWidth()) : "?";
        KText widthLabelText = _kContainerRenderingExtensions.addText(widthLabelContainer, widthLabel);
        _kRenderingExtensions.setHorizontalAlignment(widthLabelText, HorizontalAlignment.LEFT);
        _kRenderingExtensions.setVerticalAlignment(widthLabelText, VerticalAlignment.BOTTOM);
        _kRenderingExtensions.setFontSize(widthLabelText, 6);
        _linguaFrancaStyleExtensions.noSelectionStyle(widthLabelText);
        associateWith(widthLabelText, reactorInstance.getDefinition().getWidthSpec());
        return new ReactorFigureComponents(container, figure, bank);
    } else {
        return new ReactorFigureComponents(figure, figure, List.of(figure));
    }
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) KArc(de.cau.cs.kieler.klighd.krendering.KArc) Arc(de.cau.cs.kieler.klighd.krendering.Arc) PortSide(org.eclipse.elk.core.options.PortSide) KLabelExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KLabelExtensions) Extension(org.eclipse.xtext.xbase.lib.Extension) AbstractSynthesisExtensions(org.lflang.diagram.synthesis.AbstractSynthesisExtensions) KEdgeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions) KAreaPlacementData(de.cau.cs.kieler.klighd.krendering.KAreaPlacementData) KContainerRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions) KRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions) KDecoratorPlacementData(de.cau.cs.kieler.klighd.krendering.KDecoratorPlacementData) KPolyline(de.cau.cs.kieler.klighd.krendering.KPolyline) LineStyle(de.cau.cs.kieler.klighd.krendering.LineStyle) VerticalAlignment(de.cau.cs.kieler.klighd.krendering.VerticalAlignment) LinguaFrancaSynthesis(org.lflang.diagram.synthesis.LinguaFrancaSynthesis) PositionReferenceY(de.cau.cs.kieler.klighd.krendering.extensions.PositionReferenceY) PositionReferenceX(de.cau.cs.kieler.klighd.krendering.extensions.PositionReferenceX) DiagramSyntheses(de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses) KPolygon(de.cau.cs.kieler.klighd.krendering.KPolygon) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPolylineExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KPolylineExtensions) KPortExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KPortExtensions) KEllipse(de.cau.cs.kieler.klighd.krendering.KEllipse) List(java.util.List) UtilityExtensions(org.lflang.diagram.synthesis.util.UtilityExtensions) KColorExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KColorExtensions) Pair(org.eclipse.xtext.xbase.lib.Pair) StringExtensions(org.eclipse.xtext.xbase.lib.StringExtensions) KGridPlacement(de.cau.cs.kieler.klighd.krendering.KGridPlacement) KPosition(de.cau.cs.kieler.klighd.krendering.KPosition) KNodeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KNodeExtensions) ReactionPortAdjustment(org.lflang.diagram.synthesis.postprocessor.ReactionPortAdjustment) ArrayList(java.util.ArrayList) Inject(javax.inject.Inject) KlighdConstants(de.cau.cs.kieler.klighd.KlighdConstants) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) TimerInstance(org.lflang.generator.TimerInstance) KText(de.cau.cs.kieler.klighd.krendering.KText) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KRoundedRectangle(de.cau.cs.kieler.klighd.krendering.KRoundedRectangle) Property(org.eclipse.elk.graph.properties.Property) KRenderingFactory(de.cau.cs.kieler.klighd.krendering.KRenderingFactory) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) ReactionInstance(org.lflang.generator.ReactionInstance) ReactorInstance(org.lflang.generator.ReactorInstance) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) ViewSynthesisShared(de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) Colors(de.cau.cs.kieler.klighd.krendering.Colors) HorizontalAlignment(de.cau.cs.kieler.klighd.krendering.HorizontalAlignment) Function1(org.eclipse.xtext.xbase.lib.Functions.Function1) ArrayList(java.util.ArrayList) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) KRoundedRectangle(de.cau.cs.kieler.klighd.krendering.KRoundedRectangle) KGridPlacement(de.cau.cs.kieler.klighd.krendering.KGridPlacement) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) KText(de.cau.cs.kieler.klighd.krendering.KText) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering)

Example 2 with KRendering

use of de.cau.cs.kieler.klighd.krendering.KRendering in project lingua-franca by lf-lang.

the class InterfaceDependenciesVisualization method updateInterfaceDependencyVisibility.

/**
 * Updates the visibility of interface dependencies edges based on the expansion state.
 */
public static void updateInterfaceDependencyVisibility(KNode node, boolean expanded) {
    Iterable<KEdge> edges = IterableExtensions.filter(node.getOutgoingEdges(), it -> {
        return it.getProperty(INTERFACE_DEPENDENCY);
    });
    Iterable<Iterable<KRendering>> renders = IterableExtensions.map(edges, (KEdge it) -> {
        return Iterables.<KRendering>filter(it.getData(), KRendering.class);
    });
    Iterables.concat(renders).forEach(it -> {
        KInvisibility inv = IterableExtensions.last(Iterables.filter(it.getStyles(), KInvisibility.class));
        if (inv == null) {
            inv = KRenderingFactory.eINSTANCE.createKInvisibility();
            it.getStyles().add(inv);
        }
        inv.setInvisible(expanded);
    });
}
Also used : KInvisibility(de.cau.cs.kieler.klighd.krendering.KInvisibility) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering)

Example 3 with KRendering

use of de.cau.cs.kieler.klighd.krendering.KRendering in project lingua-franca by lf-lang.

the class InterfaceDependenciesVisualization method addInterfaceDependencies.

/**
 * Adds interface dependencies to the node if this option is active.
 * Visibility will be adjusted based on expansion state.
 */
public Spacing addInterfaceDependencies(KNode node, boolean expanded) {
    Spacing marginInit = null;
    if (getBooleanValue(SHOW_INTERFACE_DEPENDENCIES)) {
        List<Pair<KPort, KPort>> deps = getPortDependencies(node);
        if (!deps.isEmpty()) {
            for (Pair<KPort, KPort> pair : deps) {
                createDependencyEdge(pair, expanded);
            }
            // Fix content (label) of collapsed rendering
            KContainerRendering contentContainer = IterableExtensions.findFirst(Iterables.filter(node.getData(), KContainerRendering.class), it -> {
                return it.getProperty(KlighdProperties.COLLAPSED_RENDERING);
            });
            if (contentContainer != null) {
                if (!contentContainer.getProperty(LinguaFrancaShapeExtensions.REACTOR_CONTENT_CONTAINER)) {
                    contentContainer = IteratorExtensions.findFirst(Iterators.filter(contentContainer.eAllContents(), KContainerRendering.class), it -> {
                        return it.getProperty(LinguaFrancaShapeExtensions.REACTOR_CONTENT_CONTAINER);
                    });
                }
                if (contentContainer != null) {
                    List<KRendering> content = ImmutableList.copyOf(contentContainer.getChildren());
                    // Put into two new containers such that they are not centered/maximized
                    KRectangle firstContainer = _kContainerRenderingExtensions.addRectangle(contentContainer);
                    _kRenderingExtensions.setInvisible(firstContainer, true);
                    KRectangle secondContainer = _kContainerRenderingExtensions.addRectangle(firstContainer);
                    _kRenderingExtensions.setInvisible(secondContainer, true);
                    _kContainerRenderingExtensions.setGridPlacement(secondContainer, 1);
                    Iterables.addAll(secondContainer.getChildren(), content);
                    _kRenderingExtensions.setPointPlacementData(secondContainer, _kRenderingExtensions.LEFT, 0, 0.5f, _kRenderingExtensions.TOP, 0, 0, _kRenderingExtensions.H_CENTRAL, _kRenderingExtensions.V_TOP, 0, 0, 0, 0);
                    // Adjust ports separate dependency edges from label/content
                    if (content.size() > 0) {
                        marginInit = _utilityExtensions.getPortMarginsInitIfAbsent(node).add(new ElkMargin((content.size() * 20) - 8, 0, 0, 0));
                    }
                }
            }
        }
    }
    return marginInit;
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) Iterables(com.google.common.collect.Iterables) ElkMargin(org.eclipse.elk.core.math.ElkMargin) Spacing(org.eclipse.elk.core.math.Spacing) LinguaFrancaStyleExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaStyleExtensions) Inject(com.google.inject.Inject) Random(java.util.Random) Extension(org.eclipse.xtext.xbase.lib.Extension) AbstractSynthesisExtensions(org.lflang.diagram.synthesis.AbstractSynthesisExtensions) Iterators(com.google.common.collect.Iterators) KEdgeExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions) KContainerRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions) KRenderingExtensions(de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions) KPolyline(de.cau.cs.kieler.klighd.krendering.KPolyline) LineStyle(de.cau.cs.kieler.klighd.krendering.LineStyle) ImmutableList(com.google.common.collect.ImmutableList) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) LinguaFrancaSynthesis(org.lflang.diagram.synthesis.LinguaFrancaSynthesis) DiagramSyntheses(de.cau.cs.kieler.klighd.syntheses.DiagramSyntheses) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KInvisibility(de.cau.cs.kieler.klighd.krendering.KInvisibility) SynthesisOption(de.cau.cs.kieler.klighd.SynthesisOption) Property(org.eclipse.elk.graph.properties.Property) KRenderingFactory(de.cau.cs.kieler.klighd.krendering.KRenderingFactory) Set(java.util.Set) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) LinguaFrancaShapeExtensions(org.lflang.diagram.synthesis.styles.LinguaFrancaShapeExtensions) Sets(com.google.common.collect.Sets) IteratorExtensions(org.eclipse.xtext.xbase.lib.IteratorExtensions) List(java.util.List) IterableExtensions(org.eclipse.xtext.xbase.lib.IterableExtensions) KlighdProperties(de.cau.cs.kieler.klighd.util.KlighdProperties) ViewSynthesisShared(de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) Pair(org.eclipse.xtext.xbase.lib.Pair) Spacing(org.eclipse.elk.core.math.Spacing) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KContainerRendering(de.cau.cs.kieler.klighd.krendering.KContainerRendering) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) Pair(org.eclipse.xtext.xbase.lib.Pair) KRectangle(de.cau.cs.kieler.klighd.krendering.KRectangle) ElkMargin(org.eclipse.elk.core.math.ElkMargin)

Example 4 with KRendering

use of de.cau.cs.kieler.klighd.krendering.KRendering in project lingua-franca by lf-lang.

the class ModeDiagrams method addTransitionFigure.

private void addTransitionFigure(KEdge edge, Transition transition) {
    var spline = _kEdgeExtensions.addSpline(edge);
    _kRenderingExtensions.setLineWidth(spline, 1.5f);
    _kRenderingExtensions.setForeground(spline, MODE_FG);
    _kRenderingExtensions.setBackground(spline, MODE_FG);
    _linguaFrancaStyleExtensions.boldLineSelectionStyle(spline);
    if (transition.type == ModeTransitionType.HISTORY) {
        addHistoryDecorator(spline);
    } else {
        KRendering arrowDecorator = _kPolylineExtensions.addHeadArrowDecorator(spline);
        this._kRenderingExtensions.setForeground(arrowDecorator, MODE_FG);
        this._kRenderingExtensions.setBackground(arrowDecorator, MODE_FG);
    }
    if (getBooleanValue(SHOW_TRANSITION_LABELS)) {
        associateWith(spline, transition.getDefinition());
        KLabel centerEdgeLabel = _kLabelExtensions.addCenterEdgeLabel(edge, this.toTransitionLabel(transition));
        associateWith(centerEdgeLabel, transition.getDefinition());
        applyTransitionOnEdgeStyle(centerEdgeLabel);
    }
}
Also used : KLabel(de.cau.cs.kieler.klighd.kgraph.KLabel) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering)

Example 5 with KRendering

use of de.cau.cs.kieler.klighd.krendering.KRendering in project lingua-franca by lf-lang.

the class LinguaFrancaSynthesis method transformReactorNetwork.

private Collection<KNode> transformReactorNetwork(ReactorInstance reactorInstance, Map<PortInstance, KPort> parentInputPorts, Map<PortInstance, KPort> parentOutputPorts, Map<ReactorInstance, KNode> allReactorNodes) {
    List<KNode> nodes = new ArrayList<>();
    Table<ReactorInstance, PortInstance, KPort> inputPorts = HashBasedTable.create();
    Table<ReactorInstance, PortInstance, KPort> outputPorts = HashBasedTable.create();
    Map<ReactionInstance, KNode> reactionNodes = new HashMap<>();
    Map<KPort, KNode> directConnectionDummyNodes = new HashMap<>();
    Multimap<ActionInstance, KPort> actionDestinations = HashMultimap.create();
    Multimap<ActionInstance, KPort> actionSources = HashMultimap.create();
    Map<TimerInstance, KNode> timerNodes = new HashMap<>();
    KNode startupNode = _kNodeExtensions.createNode();
    boolean startupUsed = false;
    KNode shutdownNode = _kNodeExtensions.createNode();
    boolean shutdownUsed = false;
    // Transform instances
    int index = 0;
    for (ReactorInstance child : ListExtensions.reverseView(reactorInstance.children)) {
        Boolean expansionState = MemorizingExpandCollapseAction.getExpansionState(child);
        Collection<KNode> rNodes = createReactorNode(child, expansionState != null ? expansionState : false, inputPorts, outputPorts, allReactorNodes);
        setLayoutOption(IterableExtensions.<KNode>head(rNodes), CoreOptions.PRIORITY, index);
        nodes.addAll(rNodes);
        index++;
    }
    // Create timers
    for (TimerInstance timer : reactorInstance.timers) {
        KNode node = associateWith(_kNodeExtensions.createNode(), timer.getDefinition());
        NamedInstanceUtil.linkInstance(node, timer);
        _utilityExtensions.setID(node, timer.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(timer.getDefinition(), node));
        timerNodes.put(timer, node);
        _linguaFrancaShapeExtensions.addTimerFigure(node, timer);
    }
    // Create reactions
    for (ReactionInstance reaction : ListExtensions.reverseView(reactorInstance.reactions)) {
        int idx = reactorInstance.reactions.indexOf(reaction);
        KNode node = associateWith(_kNodeExtensions.createNode(), reaction.getDefinition());
        NamedInstanceUtil.linkInstance(node, reaction);
        _utilityExtensions.setID(node, reaction.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(reaction.getDefinition(), node));
        reactionNodes.put(reaction, node);
        setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
        // always place with higher priority than reactor nodes
        setLayoutOption(node, CoreOptions.PRIORITY, (reactorInstance.reactions.size() - idx) * 10);
        // try order reactions vertically if in one layer
        setLayoutOption(node, LayeredOptions.POSITION, new KVector(0, idx));
        _linguaFrancaShapeExtensions.addReactionFigure(node, reaction);
        // connect input
        KPort port = null;
        for (TriggerInstance<?> trigger : reaction.triggers) {
            port = addInvisiblePort(node);
            setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST);
            int triggersSize = reaction.triggers != null ? reaction.triggers.size() : 0;
            int sourcesSize = reaction.sources != null ? reaction.sources.size() : 0;
            if (getBooleanValue(REACTIONS_USE_HYPEREDGES) || triggersSize + sourcesSize == 1) {
                // manual adjustment disabling automatic one
                setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, (double) -LinguaFrancaShapeExtensions.REACTION_POINTINESS);
            }
            if (trigger.isStartup()) {
                connect(createDependencyEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition), startupNode, port);
                startupUsed = true;
            } else if (trigger.isShutdown()) {
                connect(createDelayEdge(((TriggerInstance.BuiltinTriggerVariable) trigger.getDefinition()).definition), shutdownNode, port);
                shutdownUsed = true;
            } else if (trigger instanceof ActionInstance) {
                actionDestinations.put(((ActionInstance) trigger), port);
            } else if (trigger instanceof PortInstance) {
                KPort src = null;
                PortInstance triggerAsPort = (PortInstance) trigger;
                if (triggerAsPort.getParent() == reactorInstance) {
                    src = parentInputPorts.get(trigger);
                } else {
                    src = outputPorts.get(triggerAsPort.getParent(), trigger);
                }
                if (src != null) {
                    connect(createDependencyEdge(triggerAsPort.getDefinition()), src, port);
                }
            } else if (trigger instanceof TimerInstance) {
                KNode src = timerNodes.get(trigger);
                if (src != null) {
                    connect(createDependencyEdge(trigger.getDefinition()), src, port);
                }
            }
        }
        // port = null // create new ports
        for (TriggerInstance<?> dep : reaction.sources) {
            if (reaction.triggers.contains(dep))
                continue;
            if (!(getBooleanValue(REACTIONS_USE_HYPEREDGES) && port != null)) {
                port = addInvisiblePort(node);
                setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.WEST);
                int triggersSize = reaction.triggers != null ? reaction.triggers.size() : 0;
                int sourcesSize = reaction.sources != null ? reaction.sources.size() : 0;
                if (getBooleanValue(REACTIONS_USE_HYPEREDGES) || triggersSize + sourcesSize == 1) {
                    // manual adjustment disabling automatic one
                    setLayoutOption(port, CoreOptions.PORT_BORDER_OFFSET, (double) -LinguaFrancaShapeExtensions.REACTION_POINTINESS);
                }
            }
            if (dep instanceof PortInstance) {
                KPort src = null;
                PortInstance depAsPort = (PortInstance) dep;
                if (dep.getParent() == reactorInstance) {
                    src = parentInputPorts.get(dep);
                } else {
                    src = outputPorts.get(depAsPort.getParent(), dep);
                }
                if (src != null) {
                    connect(createDependencyEdge(dep.getDefinition()), src, port);
                }
            }
        }
        // connect outputs
        // create new ports
        port = null;
        Set<TriggerInstance<?>> iterSet = reaction.effects != null ? reaction.effects : new HashSet<>();
        for (TriggerInstance<?> effect : iterSet) {
            port = addInvisiblePort(node);
            setLayoutOption(port, CoreOptions.PORT_SIDE, PortSide.EAST);
            if (effect instanceof ActionInstance) {
                actionSources.put((ActionInstance) effect, port);
            } else if (effect instanceof PortInstance) {
                KPort dst = null;
                PortInstance effectAsPort = (PortInstance) effect;
                if (effectAsPort.isOutput()) {
                    dst = parentOutputPorts.get(effect);
                } else {
                    dst = inputPorts.get(effectAsPort.getParent(), effect);
                }
                if (dst != null) {
                    connect(createDependencyEdge(effect), port, dst);
                }
            }
        }
    }
    // Connect actions
    Set<ActionInstance> actions = new HashSet<>();
    actions.addAll(actionSources.keySet());
    actions.addAll(actionDestinations.keySet());
    for (ActionInstance action : actions) {
        KNode node = associateWith(_kNodeExtensions.createNode(), action.getDefinition());
        NamedInstanceUtil.linkInstance(node, action);
        _utilityExtensions.setID(node, action.uniqueID());
        nodes.add(node);
        Iterables.addAll(nodes, createUserComments(action.getDefinition(), node));
        setLayoutOption(node, CoreOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_SIDE);
        Pair<KPort, KPort> ports = _linguaFrancaShapeExtensions.addActionFigureAndPorts(node, action.isPhysical() ? "P" : "L");
        // TODO handle variables?
        if (action.getMinDelay() != null && action.getMinDelay() != ActionInstance.DEFAULT_MIN_DELAY) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("min delay: %s", action.getMinDelay().toString()), 7);
        }
        // TODO default value?
        if (action.getDefinition().getMinSpacing() != null) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("min spacing: %s", action.getMinSpacing().toString()), 7);
        }
        if (!StringExtensions.isNullOrEmpty(action.getDefinition().getPolicy())) {
            _kLabelExtensions.addOutsideBottomCenteredNodeLabel(node, String.format("policy: %s", action.getPolicy().toString()), 7);
        }
        // connect source
        for (KPort source : actionSources.get(action)) {
            connect(createDelayEdge(action), source, ports.getKey());
        }
        // connect targets
        for (KPort target : actionDestinations.get(action)) {
            connect(createDelayEdge(action), ports.getValue(), target);
        }
    }
    // Transform connections.
    // First, collect all the source ports.
    List<PortInstance> sourcePorts = new LinkedList<>(reactorInstance.inputs);
    for (ReactorInstance child : reactorInstance.children) {
        sourcePorts.addAll(child.outputs);
    }
    for (PortInstance leftPort : sourcePorts) {
        KPort source = leftPort.getParent() == reactorInstance ? parentInputPorts.get(leftPort) : outputPorts.get(leftPort.getParent(), leftPort);
        for (SendRange sendRange : leftPort.getDependentPorts()) {
            for (RuntimeRange<PortInstance> rightRange : sendRange.destinations) {
                PortInstance rightPort = rightRange.instance;
                KPort target = rightPort.getParent() == reactorInstance ? parentOutputPorts.get(rightPort) : inputPorts.get(rightPort.getParent(), rightPort);
                // There should be a connection, but skip if not.
                Connection connection = sendRange.connection;
                if (connection != null) {
                    KEdge edge = createIODependencyEdge(connection, (leftPort.isMultiport() || rightPort.isMultiport()));
                    if (connection.getDelay() != null) {
                        KLabel delayLabel = _kLabelExtensions.addCenterEdgeLabel(edge, ASTUtils.toText(connection.getDelay()));
                        associateWith(delayLabel, connection.getDelay());
                        if (connection.isPhysical()) {
                            _linguaFrancaStyleExtensions.applyOnEdgePysicalDelayStyle(delayLabel, reactorInstance.isMainOrFederated() ? Colors.WHITE : Colors.GRAY_95);
                        } else {
                            _linguaFrancaStyleExtensions.applyOnEdgeDelayStyle(delayLabel);
                        }
                    } else if (connection.isPhysical()) {
                        KLabel physicalConnectionLabel = _kLabelExtensions.addCenterEdgeLabel(edge, "---");
                        _linguaFrancaStyleExtensions.applyOnEdgePysicalStyle(physicalConnectionLabel, reactorInstance.isMainOrFederated() ? Colors.WHITE : Colors.GRAY_95);
                    }
                    if (source != null && target != null) {
                        // check for inside loop (direct in -> out connection with delay)
                        if (parentInputPorts.values().contains(source) && parentOutputPorts.values().contains(target)) {
                            // edge.setLayoutOption(CoreOptions.INSIDE_SELF_LOOPS_YO, true) // Does not work as expected
                            // Introduce dummy node to enable direct connection (that is also hidden when collapsed)
                            KNode dummy = _kNodeExtensions.createNode();
                            if (directConnectionDummyNodes.containsKey(target)) {
                                dummy = directConnectionDummyNodes.get(target);
                            } else {
                                nodes.add(dummy);
                                directConnectionDummyNodes.put(target, dummy);
                                _kRenderingExtensions.addInvisibleContainerRendering(dummy);
                                _kNodeExtensions.setNodeSize(dummy, 0, 0);
                                KEdge extraEdge = createIODependencyEdge(null, (leftPort.isMultiport() || rightPort.isMultiport()));
                                connect(extraEdge, dummy, target);
                            }
                            connect(edge, source, dummy);
                        } else {
                            connect(edge, source, target);
                        }
                    }
                }
            }
        }
    }
    // Add startup/shutdown
    if (startupUsed) {
        _linguaFrancaShapeExtensions.addStartupFigure(startupNode);
        nodes.add(0, startupNode);
        setLayoutOption(startupNode, LayeredOptions.LAYERING_LAYER_CONSTRAINT, LayerConstraint.FIRST);
        if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
            KPort port = addInvisiblePort(startupNode);
            startupNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    if (shutdownUsed) {
        _linguaFrancaShapeExtensions.addShutdownFigure(shutdownNode);
        nodes.add(0, shutdownNode);
        if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
            // connect all edges to one port
            KPort port = addInvisiblePort(shutdownNode);
            shutdownNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    // Postprocess timer nodes
    if (getBooleanValue(REACTIONS_USE_HYPEREDGES)) {
        // connect all edges to one port
        for (KNode timerNode : timerNodes.values()) {
            KPort port = addInvisiblePort(timerNode);
            timerNode.getOutgoingEdges().forEach(it -> {
                it.setSourcePort(port);
            });
        }
    }
    // Add reaction order edges (add last to have them on top of other edges)
    if (reactorInstance.reactions.size() > 1) {
        KNode prevNode = reactionNodes.get(IterableExtensions.head(reactorInstance.reactions));
        Iterable<KNode> iterList = IterableExtensions.map(IterableExtensions.drop(reactorInstance.reactions, 1), reactionNodes::get);
        for (KNode node : iterList) {
            KEdge edge = createOrderEdge();
            edge.setSource(prevNode);
            edge.setTarget(node);
            edge.setProperty(CoreOptions.NO_LAYOUT, true);
            // Do not remove them, as they are needed for cycle detection
            KRendering edgeRendering = _kRenderingExtensions.getKRendering(edge);
            _kRenderingExtensions.setInvisible(edgeRendering, !getBooleanValue(SHOW_REACTION_ORDER_EDGES));
            _kRenderingExtensions.getInvisible(edgeRendering).setPropagateToChildren(true);
            // TODO this does not work work with incremental update (https://github.com/kieler/KLighD/issues/37)
            // if (!getBooleanValue(SHOW_REACTION_ORDER_EDGES)) edge.initiallyHide()
            prevNode = node;
        }
    }
    _modeDiagrams.handleModes(nodes, reactorInstance);
    return nodes;
}
Also used : PortInstance(org.lflang.generator.PortInstance) ReactionInstance(org.lflang.generator.ReactionInstance) HashMap(java.util.HashMap) TimerInstance(org.lflang.generator.TimerInstance) ArrayList(java.util.ArrayList) KVector(org.eclipse.elk.core.math.KVector) KRendering(de.cau.cs.kieler.klighd.krendering.KRendering) HashSet(java.util.HashSet) Connection(org.lflang.lf.Connection) KEdge(de.cau.cs.kieler.klighd.kgraph.KEdge) KPort(de.cau.cs.kieler.klighd.kgraph.KPort) KNode(de.cau.cs.kieler.klighd.kgraph.KNode) TriggerInstance(org.lflang.generator.TriggerInstance) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) LayerConstraint(org.eclipse.elk.alg.layered.options.LayerConstraint) LinkedList(java.util.LinkedList) KLabel(de.cau.cs.kieler.klighd.kgraph.KLabel) ReactorInstance(org.lflang.generator.ReactorInstance) ActionInstance(org.lflang.generator.ActionInstance) SendRange(org.lflang.generator.SendRange)

Aggregations

KRendering (de.cau.cs.kieler.klighd.krendering.KRendering)10 KEdge (de.cau.cs.kieler.klighd.kgraph.KEdge)6 KPolyline (de.cau.cs.kieler.klighd.krendering.KPolyline)6 KNode (de.cau.cs.kieler.klighd.kgraph.KNode)5 KPort (de.cau.cs.kieler.klighd.kgraph.KPort)5 KRectangle (de.cau.cs.kieler.klighd.krendering.KRectangle)5 KText (de.cau.cs.kieler.klighd.krendering.KText)5 ReactorInstance (org.lflang.generator.ReactorInstance)5 KLabel (de.cau.cs.kieler.klighd.kgraph.KLabel)4 KContainerRendering (de.cau.cs.kieler.klighd.krendering.KContainerRendering)4 LineStyle (de.cau.cs.kieler.klighd.krendering.LineStyle)4 ViewSynthesisShared (de.cau.cs.kieler.klighd.krendering.ViewSynthesisShared)4 KContainerRenderingExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KContainerRenderingExtensions)4 KEdgeExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KEdgeExtensions)4 KRenderingExtensions (de.cau.cs.kieler.klighd.krendering.extensions.KRenderingExtensions)4 ArrayList (java.util.ArrayList)4 List (java.util.List)4 Iterables (com.google.common.collect.Iterables)3 SynthesisOption (de.cau.cs.kieler.klighd.SynthesisOption)3 Colors (de.cau.cs.kieler.klighd.krendering.Colors)3