X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fprofile%2FTextGridStyle.java;fp=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fprofile%2FTextGridStyle.java;h=03069a3df66b7056445dd3adcf4913ae4cd9b879;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/TextGridStyle.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/TextGridStyle.java new file mode 100644 index 000000000..03069a3df --- /dev/null +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/TextGridStyle.java @@ -0,0 +1,367 @@ +package org.simantics.diagram.profile; + +import java.awt.Color; +import java.awt.Font; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.simantics.databoard.Bindings; +import org.simantics.datatypes.literal.Vec2d; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.RVI; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.diagram.elements.ITextListener; +import org.simantics.diagram.elements.TextGridNode; +import org.simantics.diagram.elements.TextNode; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.g2d.utils.Alignment; +import org.simantics.modeling.ModelingResources; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.g2d.nodes.ConnectionNode; +import org.simantics.scenegraph.profile.EvaluationContext; +import org.simantics.scenegraph.profile.common.ProfileVariables; +import org.simantics.scenegraph.utils.GeometryUtils; +import org.simantics.scenegraph.utils.NodeUtil; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.ui.colors.Colors; + +/** + * @author Antti Villberg + * @author Tuukka Lehtonen + */ +public abstract class TextGridStyle extends StyleBase { + + private final Font FONT = Font.decode("Arial 12"); + private final Color BACKGROUND_COLOR = new Color(255, 255, 255, 192); + private static final Rectangle2D EMPTY_BOUNDS = new Rectangle2D.Double(0, 0, 0, 0); + + // NOTE: this is a hack + String id; + + protected double xOffset; + protected double yOffset; + + public TextGridStyle() { + this(0.0, 2.1); + } + + public TextGridStyle(double xOffset, double yOffset) { + this.xOffset = xOffset; + this.yOffset = yOffset; + } + + public Resource getPropertyRelation(ReadGraph g, Resource module) { + throw new Error("Fix this"); + } + + /** + * @return the name of the scene graph node to create to represent the text + * element created by this style + */ + public String getNodeName() { + return getClass().getSimpleName(); + } + + /** + * Override to customize. + * + * @param graph + * @param element + * @return + * @throws DatabaseException + */ + protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException { + ModelingResources mr = ModelingResources.getInstance(graph); + Resource config = graph.getPossibleObject(element, mr.ElementToComponent); + return config; + } + + /** + * Override to customize. + * + * @param graph + * @param element + * @return + * @throws DatabaseException + */ + protected String getConfigurationComponentNameForElement(ReadGraph graph, Resource element) throws DatabaseException { + Resource config = getConfigurationComponent(graph, element); + if (config == null) + return null; + String name = graph.getPossibleRelatedValue(config, getPropertyRelation(graph,element), Bindings.STRING); + return name; + } + + public AffineTransform getTransform(INode node, AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) { + return getTransform(parentTransform, elementBounds, location, up); + } + + public AffineTransform getTransform(AffineTransform parentTransform, Rectangle2D elementBounds, int location, boolean up) { + + double scale = GeometryUtils.getScale(parentTransform); + + AffineTransform at = AffineTransform.getTranslateInstance( + parentTransform.getTranslateX() + elementBounds.getCenterX() * scale + xOffset, + parentTransform.getTranslateY() + elementBounds.getMinY() * scale + yOffset*(location-1) + (up ? 0.0 : (2.0*yOffset) + elementBounds.getHeight() * scale) + ); + at.scale(0.15, 0.15); + + return at; + + } + + protected String rowId() { + return ""; + } + + @Override + public MonitorTextGridResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) + throws DatabaseException { + String name = getConfigurationComponentNameForElement(graph, element); + if (name == null) + return null; + AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element); + Vec2d offset = DiagramGraphUtil.getOffset(graph, element); + boolean enabled = !DiagramGraphUtil.getProfileMonitorsHidden(graph, element); + boolean up = DiagramGraphUtil.getProfileMonitorsUp(graph, element); + double spacing = DiagramGraphUtil.getProfileMonitorSpacing(graph, element); + return new MonitorTextGridResult(rowId(), name, "", "", enabled, up, spacing, null, null, null, transform, offset); + } + + // Not to be modified + protected final static Point2D[] DEFAULT_CELL_OFFSETS = new Point2D[] { + new Point2D.Double(-45, 0), + new Point2D.Double(22, 0), + new Point2D.Double(24, 0) + }; + + // Not to be modified + protected final static Point2D[] ZERO_CELL_OFFSETS = new Point2D[] { + new Point2D.Double(0, 0), + new Point2D.Double(0, 0), + new Point2D.Double(0, 0) + }; + + protected Point2D[] getCellOffsets() { + return DEFAULT_CELL_OFFSETS; + } + + @Override + public void applyStyleForNode(EvaluationContext observer, INode _node, MonitorTextGridResult result) { + + String value = result != null ? result.getText1() : null; + boolean enabled = result != null ? result.getEnabled() : false; + + if (value != null && enabled) { + + // if (value != null && !value.isEmpty() && !value.trim().isEmpty()) { + + String value2 = result != null ? result.getText2() : null; + String value3 = result != null ? result.getText3() : null; + + double spacing = result.getSpacing(); + + final Function1 modifier = result != null ? result.getModifier() : null; + final Function1 validator = result != null ? result.getValidator() : null; + final Function1 translator = result != null ? result.getTranslator() : null; + final RVI rvi = result != null ? result.getRVI() : null; + + final TextGridNode node = ProfileVariables.claimChild(_node, "", "TextGridStyle", TextGridNode.class, observer); + if (node == null) + return; + + // This assumes that this TextGridStyle instance will be devoted to + // this row ID until the end of its life. + String id = result.getRowId(); + //System.out.println(this + " ID: " + id); + if (!id.equals(this.id)) { + //System.out.println(this + " SET ID: " + this.id + " -> " + id); + this.id = id; + } + + Integer newRow = observer.getTemporaryProperty(_node, "location"); + if (newRow == null) + newRow = 1; + + // Remove from existing row to add to another row if necessary. + Integer row = observer.getProperty(_node, id); + if (row != null && row != newRow) { + String actualId = node.getRowId(row); + if (id.equals(actualId)) { + node.removeRow(row); + } + } + row = newRow; + + node.setRowId(row, id); + observer.setProperty(_node, id, row); + observer.setTemporaryProperty(_node, "location", row + 1); + + node.setText(2, row, value2); + node.setUp(result.getUp()); + + MonitorTextGridResult cache = node.getCache(1, row); + if(cache != null && cache.sameStructure(result)) return; + + node.setCache(1, row, result); + + boolean isConnection = _node instanceof ConnectionNode; + + Rectangle2D elementBounds = isConnection ? EMPTY_BOUNDS : NodeUtil.getLocalElementBounds(_node); + if(elementBounds == null) { + new Exception("Cannot get local element bounds for node " + _node.toString()).printStackTrace(); + // This is here for checking why getLocalElementBounds failed in the debugger. + NodeUtil.getLocalElementBounds(_node); + return; + } + + // System.err.println("elementBounds " + elementBounds); + // System.err.println("parentTransform " + result.getParentTransform()); + + AffineTransform at = getTransform(_node,result.getParentTransform(), elementBounds, row, result.getUp()); + Vec2d offset = result.getOffset(); + + Point2D[] cellOffsets = getCellOffsets(); + + AffineTransform at1 = new AffineTransform(at); + at1.translate(cellOffsets[0].getX(),cellOffsets[0].getY()); + AffineTransform at2 = new AffineTransform(at); + at2.translate(cellOffsets[1].getX()+spacing,cellOffsets[1].getY()); + AffineTransform at3 = new AffineTransform(at); + at3.translate(cellOffsets[2].getX()+spacing,cellOffsets[2].getY()); + + at1.translate(offset.x, offset.y); + at2.translate(offset.x, offset.y); + at3.translate(offset.x, offset.y); + + node.setTransform(1, row, at1); + node.setTransform(2, row, at2); + node.setTransform(3, row, at3); + + Alignment[] alignments = result.getAlignments(); + if(alignments != null) { + node.setHorizontalAlignment(1, row, (byte) alignments[0].ordinal()); + node.setHorizontalAlignment(2, row, (byte) alignments[1].ordinal()); + node.setHorizontalAlignment(3, row, (byte) alignments[2].ordinal()); + } else { + node.setHorizontalAlignment(1, row, (byte) getAlignment(1).ordinal()); + node.setHorizontalAlignment(2, row, (byte) getAlignment(2).ordinal()); + node.setHorizontalAlignment(3, row, (byte) getAlignment(3).ordinal()); + } + + Alignment[] verticalAlignments = result.getVerticalAlignments(); + if(verticalAlignments != null) { + node.setVerticalAlignment(1, row, (byte) verticalAlignments[0].ordinal()); + node.setVerticalAlignment(2, row, (byte) verticalAlignments[1].ordinal()); + node.setVerticalAlignment(3, row, (byte) verticalAlignments[2].ordinal()); + } else { + node.setVerticalAlignment(1, row, (byte) getVerticalAlignment(1).ordinal()); + node.setVerticalAlignment(2, row, (byte) getVerticalAlignment(2).ordinal()); + node.setVerticalAlignment(3, row, (byte) getVerticalAlignment(3).ordinal()); + } + + node.setZIndex(3000); + + org.simantics.common.color.Color color = result.getColor(); + java.awt.Color awtColor = color != null ? Colors.awt(color) : Color.DARK_GRAY; + + setTextNodeData(node, 1, row, value, FONT, awtColor, BACKGROUND_COLOR); + setTextNodeData(node, 2, row, value2, result.getPending(), FONT, awtColor, BACKGROUND_COLOR); + setTextNodeData(node, 3, row, value3, FONT, awtColor, BACKGROUND_COLOR); + + node.setEditable(1, row, false); + node.setEditable(2, row, modifier != null); + node.setEditable(3, row, false); + + final int finalRow = row; + + if (modifier != null) { + node.setTextListener(2, row, new ITextListener() { + @Override + public void textChanged() {} + + @Override + public void textEditingStarted() {} + + @Override + public void textEditingCancelled() { + } + + @Override + public void textEditingEnded() { + + TextNode t = node.get(2, finalRow); + if (t == null) + return; + + if(!t.getText().equals(t.getTextBeforeEdit())) + modifier.apply(t.getText()); + + } + }); + } else { + node.setTextListener(2, row, null); + } + + node.setInputValidator(2, row, validator); + node.setTranslator(translator); + + node.setRVI(2, row, rvi); + + postProcessNode(node, row); + + } else { + cleanupStyleForNode(observer, _node); + } + } + + private void setTextNodeData(TextGridNode node, int x, int y, String text, Font font, Color fgColor, Color bgColor) { + if (text != null) { + node.setText(x, y, text); + node.setFont(x, y, font); + node.setColor(x, y, fgColor); + node.setBackgroundColor(x, y, bgColor); + } else { + // Prevent rendering of the node. + node.setFont(x, y, null); + } + } + + private void setTextNodeData(TextGridNode node, int x, int y, String text, boolean pending, Font font, Color fgColor, Color bgColor) { + setTextNodeData(node, x, y, text, font, fgColor, bgColor); + node.setPending(x, y, pending); + } + + protected Alignment getAlignment(int column) { + switch(column) { + case 1: return Alignment.TRAILING; + case 2: return Alignment.TRAILING; + case 3: return Alignment.LEADING; + default: return Alignment.LEADING; + } + } + + protected Alignment getVerticalAlignment(int column) { + return Alignment.TRAILING; + } + + @Override + protected void cleanupStyleForNode(EvaluationContext observer, INode _node) { + Integer row = observer.getProperty(_node, id); + //System.out.println(this + " cleanup(" + id + ", " + row + ")"); + //System.out.println(element); + if (row == null) + return; + observer.setProperty(_node, id, null); + TextGridNode node = ProfileVariables.browseChild(_node, "TextGridStyle"); + if (node != null) + node.removeRow(row); + } + + protected void postProcessNode(TextGridNode node, int row) { + } + +}