From cdda2dfb6cf116fde6d7c0a70c4ebb1d4c9781e9 Mon Sep 17 00:00:00 2001 From: lempinen Date: Mon, 25 Nov 2013 13:17:28 +0000 Subject: [PATCH] Editable multi-line text elements refs #2929 git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@28372 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../sysdyn/ui/elements/AuxiliaryFactory.java | 24 +- .../ui/elements/HoverTextElementHandler.java | 73 ---- .../ui/elements/HoverTextElementNoBounds.java | 341 ----------------- .../sysdyn/ui/elements/HoverTextNode.java | 180 --------- .../sysdyn/ui/elements/InputFactory.java | 8 +- .../sysdyn/ui/elements/LoopFactory.java | 4 +- .../sysdyn/ui/elements/ModuleFactory.java | 17 +- .../sysdyn/ui/elements/ModuleNode.java | 15 +- .../ui/elements/MultilineTextElement.java | 73 ---- .../elements/MultilineTextElementFactory.java | 96 +---- .../sysdyn/ui/elements/MultilineTextNode.java | 289 -------------- .../sysdyn/ui/elements/ShadowFactory.java | 6 +- .../sysdyn/ui/elements/StockFactory.java | 24 +- .../ui/elements/SysdynElementFactory.java | 12 + .../ui/elements/SysdynTextElementHandler.java | 55 +++ .../elements/SysdynTextElementNoBounds.java | 306 +++++++++++++++ .../sysdyn/ui/elements/SysdynTextNode.java | 79 ++++ .../sysdyn/ui/elements/ValveFactory.java | 356 +++++++----------- .../sysdyn/ui/elements/ValveOutline.java | 47 ++- .../RouteFlowConnectionFactory.java | 24 +- 20 files changed, 676 insertions(+), 1353 deletions(-) delete mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementHandler.java delete mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementNoBounds.java delete mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextNode.java delete mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElement.java delete mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextNode.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementHandler.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementNoBounds.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextNode.java diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryFactory.java index c25ac8ec..40e523b1 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/AuxiliaryFactory.java @@ -16,8 +16,8 @@ import java.awt.geom.Ellipse2D; import java.util.Collection; import org.simantics.db.Resource; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; import org.simantics.g2d.element.ElementClass; -import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.handler.impl.BoundsOutline; import org.simantics.g2d.element.handler.impl.DefaultTransform; import org.simantics.g2d.element.handler.impl.ObjectTerminal; @@ -32,7 +32,6 @@ import org.simantics.g2d.element.handler.impl.TextImpl; import org.simantics.g2d.image.Image; import org.simantics.g2d.image.impl.ShapeImage; import org.simantics.g2d.utils.Alignment; -import org.simantics.scenegraph.g2d.G2DParentNode; /** * @author Tuukka Lehtonen @@ -53,27 +52,12 @@ public class AuxiliaryFactory extends SysdynElementFactory { new StaticObjectAdapter(elementType), new StaticSymbolImpl(AUX_STATIC_IMAGE), StaticSymbolImageInitializer.INSTANCE, - new AuxiliarySceneGraph(0, 0, Alignment.LEADING, 0, 1.5, 1.5, true), + new SysdynTextElementHandler(0, 0, Alignment.LEADING, 0, 1.5, 1.5, true), BoundsOutline.INSTANCE, + ResizeRectangularSceneGraph.INSTANCE, + RESIZE_PROPERTY_SETTER, new WholeElementTerminals(terminals) ).setId(AuxiliaryFactory.class.getSimpleName()); } - - public static class AuxiliarySceneGraph extends HoverTextElementHandler { - - private static final long serialVersionUID = -7077873654863790864L; - - public AuxiliarySceneGraph(double i, double j, Alignment leading, double k, double d, - double e, boolean b) { - super(i, j, leading, k, d, e, b); - } - - @Override - public void init(IElement e, G2DParentNode parent) { - super.init(e, parent); - unflipText(e); - } - - } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementHandler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementHandler.java deleted file mode 100644 index 5621765a..00000000 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementHandler.java +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.sysdyn.ui.elements; - -import java.awt.Font; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - -import org.simantics.g2d.element.ElementHints; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.handler.InternalSize; -import org.simantics.g2d.utils.Alignment; - -public class HoverTextElementHandler extends HoverTextElementNoBounds implements InternalSize { - - private static final long serialVersionUID = 8800738238681432901L; - - public static final HoverTextElementHandler INSTANCE = new HoverTextElementHandler(); - - public HoverTextElementHandler() { - super(); - } - - public HoverTextElementHandler(double originX, double originY, Alignment horizontalAlignment) { - super(originX, originY, horizontalAlignment); - } - - public HoverTextElementHandler(double originX, double originY, Alignment horizontalAlignment, double borderWidth) { - super(originX, originY, horizontalAlignment, borderWidth); - } - - public HoverTextElementHandler(double originX, double originY, Alignment horizontalAlignment, double borderWidth, - double paddingX, double paddingY, boolean editable) { - super(originX, originY, horizontalAlignment, borderWidth, paddingX, paddingY, editable); - } - - @Override - public Rectangle2D getBounds(IElement e, Rectangle2D size) { - HoverTextNode node = (HoverTextNode) e.getHint(SG_NODE); - if (size == null) - size = new Rectangle2D.Double(); - if (node != null) - size.setRect(node.getBoundsInLocal()); - else { - String text = e.getHint(ElementHints.KEY_TEXT); - Font font = e.getHint(ElementHints.KEY_FONT); - if(text == null || font == null) - size.setFrame(0, 0, 0, 0); - else { - FontRenderContext FRC = new FontRenderContext(new AffineTransform(), true, true); - TextLayout tl = new TextLayout(text, font, FRC); - Rectangle2D bounds = tl.getLogicalHighlightShape(0, text.length()).getBounds2D(); - size.setFrame( - bounds.getX() * SCALE - paddingX, - bounds.getY() * SCALE -paddingY, - bounds.getWidth()* SCALE + paddingX + paddingX, - bounds.getHeight()* SCALE + paddingY + paddingY); - } - } - return size; - } -} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementNoBounds.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementNoBounds.java deleted file mode 100644 index d0076512..00000000 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextElementNoBounds.java +++ /dev/null @@ -1,341 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.sysdyn.ui.elements; - -import java.awt.Color; -import java.awt.Font; -import java.awt.geom.AffineTransform; - -import org.eclipse.swt.widgets.Control; -import org.eclipse.ui.IWorkbenchPage; -import org.simantics.db.ReadGraph; -import org.simantics.db.Resource; -import org.simantics.db.WriteGraph; -import org.simantics.db.common.request.ReadRequest; -import org.simantics.db.common.request.WriteRequest; -import org.simantics.db.exception.DatabaseException; -import org.simantics.diagram.elements.DiagramNodeUtil; -import org.simantics.diagram.elements.ITextListener; -import org.simantics.diagram.elements.TextElementNoBounds; -import org.simantics.diagram.elements.TextNode; -import org.simantics.diagram.participant.SGFocusParticipant; -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.chassis.SWTChassis; -import org.simantics.g2d.diagram.DiagramUtils; -import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.element.ElementHints; -import org.simantics.g2d.element.ElementUtils; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.handler.LifeCycle; -import org.simantics.g2d.utils.Alignment; -import org.simantics.layer0.Layer0; -import org.simantics.modeling.ModelingResources; -import org.simantics.modeling.ui.diagramEditor.DiagramEditor; -import org.simantics.modeling.ui.diagramEditor.DiagramViewer; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.sysdyn.SysdynResource; -import org.simantics.sysdyn.ui.utils.SysdynWorkbenchUtils; -import org.simantics.sysdyn.ui.utils.VariableNameValidator; -import org.simantics.ui.SimanticsUI; -import org.simantics.utils.datastructures.Callback; -import org.simantics.utils.datastructures.hints.IHintContext.Key; -import org.simantics.utils.datastructures.hints.IHintListener; -import org.simantics.utils.datastructures.hints.IHintObservable; - -/** - * ElementHandler for text elements - * In-line editing supported. - * - * @author Marko Luukkainen - */ -public class HoverTextElementNoBounds extends TextElementNoBounds implements LifeCycle { - - private static final long serialVersionUID = -148784588840819612L; - - public static final HoverTextElementNoBounds INSTANCE = new HoverTextElementNoBounds(); - - static class HoverHintListener implements IHintListener { - @Override - public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { - } - @Override - public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { - if (key == ElementHints.KEY_HOVER) { - IElement e = (IElement)sender; - TextNode name = (TextNode) e.getHint(SG_NODE); - if (name != null) - name.setHover(Boolean.TRUE.equals(e.getHint(ElementHints.KEY_HOVER))); - } - } - } - - protected static IHintListener hoverHintListener = new HoverHintListener(); - - public HoverTextElementNoBounds() { - super(0, 0, Alignment.LEADING, 0); - } - - public HoverTextElementNoBounds(double originX, double originY, Alignment horizontalAlignment) { - super(originX, originY, horizontalAlignment, 0); - } - - public HoverTextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth) { - super(originX, originY, horizontalAlignment, borderWidth); - } - - public HoverTextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable) { - super(originX, originY, horizontalAlignment, borderWidth, paddingX, paddingY, editable); - } - - protected HoverTextNode getTextNode(IElement e, G2DParentNode parent) { - return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", HoverTextNode.class, getCallback(e, parent, HoverTextNode.class)); - } - - protected Callback getCallback(final IElement e, G2DParentNode parent, Class nodeClass) { - return new Callback() { - @Override - public void run(T node) { - node.setTextListener(new ITextListener() { - - String textBeforeEdit; - Resource component; - - @Override - public void textChanged() { - TextNode node = (TextNode) e.getHint(SG_NODE); - if(!new VariableNameValidator().isValid(component, node.getText(), false)) { - node.setColor(Color.RED); - } else { - node.setColor(ElementUtils.getTextColor(e, Color.BLACK)); - } - - - } - - @Override - public void textEditingStarted() { - TextNode node = (TextNode) e.getHint(SG_NODE); - textBeforeEdit = node.getText(); - - if(component != null) return; - - Object o = e.getHint(ElementHints.KEY_OBJECT); - if(o != null && o instanceof Resource) { - final Resource element = (Resource)o; - SimanticsUI.getSession().asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - component = graph.getPossibleObject(element, ModelingResources.getInstance(graph).ElementToComponent); - } - }); - } - } - - @Override - public void textEditingCancelled() { - TextNode node = (TextNode) e.getHint(SG_NODE); - if (node != null) { - if(new VariableNameValidator().isValid(component, node.getText(), false)) - node.setColor(ElementUtils.getTextColor(e, Color.BLACK)); - endEdit(node); - } - } - - @Override - public void textEditingEnded() { - TextNode node = (TextNode) e.getHint(SG_NODE); - if (node == null) - return; - String text = node.getText(); - if(!new VariableNameValidator().isValid(component, text, false)) { - text = textBeforeEdit; - node.setText(text); - if(new VariableNameValidator().isValid(component, text, false)) - node.setColor(ElementUtils.getTextColor(e, Color.BLACK)); - } else { - Object o = e.getHint(ElementHints.KEY_OBJECT); - final String textAfterEdit = text; - if(o != null && o instanceof Resource) { - SimanticsUI.getSession().asyncRequest(new WriteRequest() { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - Resource configuration = graph.getPossibleObject(component, Layer0.getInstance(graph).PartOf); - new VariableNameValidator().renameInAllEquations(graph, configuration, textBeforeEdit, textAfterEdit); - } - }); - } - } - ElementUtils.setText(e, text); - IDiagram diagram = ElementUtils.getDiagram(e); - DiagramUtils.synchronizeHintsToBackend(diagram, e); - endEdit(node); - } - }); - } - }; - } - - public static double SCALE = 0.235; - - protected void initNode(IElement e, HoverTextNode node) { - //Font font = new Font("Tahoma", 0, 12); - Font font = ElementUtils.getTextFont(e); - Color color = ElementUtils.getTextColor(e); - Color fillColor = ElementUtils.getFillColor(e); - Color borderColor = ElementUtils.getBorderColor(e, Color.BLACK); - String text = ElementUtils.getText(e); - AffineTransform at = ElementUtils.getTransform(e); - Alignment hAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, horizontalAlignment); - node.init(text, font, color, originX, originY, SCALE); - node.setBackgroundColor(fillColor); - node.setBorderColor(borderColor); - node.setHorizontalAlignment((byte) hAlign.ordinal()); - node.setPadding(paddingX, paddingY); - node.setBorderWidth((float) borderWidth); - node.setEditable(editable); - if(at != null) - node.setTransform(at); - } - - public static void unflipText(IElement e) { - Object o = e.getHint(SG_NODE); - if (o instanceof TextNode) { - TextNode text = (TextNode)o; - AffineTransform at = text.getTransform(); - double x = at.getTranslateX(); - double y = at.getTranslateY(); - at.setToRotation(0); - at.setToTranslation(x, y); - at.setTransform(at); - } - } - - protected void activateEdit(final HoverTextNode node, final IElement e) { - final ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node); - // FIXME: needed only because eventdelegator registrations are done before adding node to scene graph. - if (ctx == null) - return; - if (!node.isEditMode()) { - - // Get the active editor - IWorkbenchPage page = SysdynWorkbenchUtils.getActivePageOfEditor(); - final DiagramEditor editor = (DiagramEditor)page.getActiveEditor(); - final ICanvasContext editorCtx = (ICanvasContext) editor.getViewer().getAdapter(ICanvasContext.class); - - editor.getViewer().getComposite().getDisplay().asyncExec(new Runnable() { - - @Override - public void run() { - Control c = editor.getViewer().getComposite().getDisplay().getFocusControl(); - if (c == null || "BasicSymbols".equals(c.getParent().getToolTipText())) { - // If the variable has been drag and dropped, set focus to diagram and then activate edit. - - editorCtx.add(new SGFocusParticipant((SWTChassis)editor.getViewer().getComposite(), DiagramViewer.DIAGRAMMING_CONTEXT) { - - @Override - public void focusGained(java.awt.event.FocusEvent event) { - - // When focus has been gained, acticate edit and destroy the listener. - editor.getViewer().getComposite().getDisplay().asyncExec(new Runnable() { - - @Override - public void run() { - if (Boolean.TRUE.equals(node.setEditMode(true))) { - node.activateEdit(0, e, ctx, true); - node.repaint(); - } - } - }); - ctx.remove(this); - } - - @Override - public void focusLost(java.awt.event.FocusEvent e) { - } - }); - - editor.setFocus(); - } else { - // If the variable has been created with shortcut key, just activate the edit. - if (Boolean.TRUE.equals(node.setEditMode(true))) { - node.activateEdit(0, e, ctx, true); - node.repaint(); - } - } - } - }); - } - } - - @Override - public void init(final IElement e, G2DParentNode parent) { - final HoverTextNode node = getTextNode(e, parent); - initNode(e, node); - - Object o = e.getHint(ElementHints.KEY_OBJECT); - if (o instanceof Resource) { - final Resource element = (Resource)o; - try { - SimanticsUI.getSession().syncRequest(new WriteRequest() { - - @Override - public void perform(WriteGraph graph) throws DatabaseException { - SysdynResource SR = SysdynResource.getInstance(graph); - ModelingResources MR = ModelingResources.getInstance(graph); - Resource component = graph.getPossibleObject(element, MR.ElementToComponent); - if (component == null) - return; - - // See if the resource of the element has just been created. - Resource r = graph.getPossibleObject(component, SR.IndependentVariable_isUninitialized); - if (r == null){ - return; - } - - // If the resource is just been created, activate editing its name. - if (!graph.isInstanceOf(r, SR.Loop)) { - activateEdit(node, e); - } - graph.deny(component, SR.IndependentVariable_isUninitialized, r); - } - }); - } catch (DatabaseException e1) { - e1.printStackTrace(); - } - } - } - - @Override - public void cleanup(IElement e) { - ElementUtils.removePossibleNode(e, SG_NODE); - } - - @Override - public void onElementCreated(IElement e) { - } - - @Override - public void onElementDestroyed(IElement e) { - } - - @Override - public void onElementActivated(IDiagram d, IElement e) { - e.addKeyHintListener(ElementHints.KEY_HOVER, hoverHintListener); - } - - @Override - public void onElementDeactivated(IDiagram d, IElement e) { - e.removeKeyHintListener(ElementHints.KEY_HOVER, hoverHintListener); - } - -} \ No newline at end of file diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextNode.java deleted file mode 100644 index 24f3ab16..00000000 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/HoverTextNode.java +++ /dev/null @@ -1,180 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.sysdyn.ui.elements; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -import org.simantics.diagram.elements.DiagramNodeUtil; -import org.simantics.diagram.elements.TextEditActivation; -import org.simantics.diagram.elements.TextNode; -import org.simantics.g2d.canvas.ICanvasContext; -import org.simantics.g2d.element.IElement; -import org.simantics.scenegraph.ISelectionPainterNode; -import org.simantics.scenegraph.g2d.events.EventTypes; -import org.simantics.scenegraph.g2d.events.FocusEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin; -import org.simantics.scenegraph.utils.NodeUtil; -import org.simantics.sysdyn.ui.utils.SysdynWorkbenchUtils; - -public class HoverTextNode extends TextNode implements ISelectionPainterNode { - - private static final long serialVersionUID = 3539499125943249895L; - - protected static transient ThreadLocal tempBounds = new ThreadLocal() { - @Override - protected Rectangle2D initialValue() { - return new Rectangle2D.Double(); - } - }; - - @Override - public void render(Graphics2D g) { - if (text == null || font == null || color == null) - return; - - AffineTransform ot = g.getTransform(); - g.transform(transform); - - boolean selected = NodeUtil.isSelected(this, 1); - if (!selected && hover){ - BasicStroke oldStroke = (BasicStroke)g.getStroke(); - Color oldColor = g.getColor(); - g.setColor(Color.LIGHT_GRAY); - g.setStroke(new BasicStroke((float)(2.0f))); - g.scale(scale, scale); - g.translate(x, y); - g.draw(expandBoundsUnscaled(getTightAlignedBoundsInLocal(tempBounds.get(), g.getFontRenderContext()))); - g.translate(-x, -y); - g.scale(scaleRecip, scaleRecip); - g.setColor(oldColor); - g.setStroke(oldStroke); - - } - - super.render(g, false); - g.setTransform(ot); - } - - @Override - public void remove() { - super.remove(); - removeEventHandler(this); - } - - @Override - public int getEventMask(){ - return EventTypes.FocusLostMask | super.getEventMask(); - } - - @Override - protected boolean handleFocusEvent(FocusEvent e) { - int eventType = EventTypes.toType(e); - if (eventType == EventTypes.FocusLost){ - //If focus of the element (and the diagram) is lost, save the name of the node - fireTextEditingEnded(); - } - return false; - } - - @Override - protected boolean mouseClicked(MouseClickEvent event) { - if (event.button != MouseClickEvent.LEFT_BUTTON) - return false; - - if (hitTest(event, 0)) { - hoverClick++; - if (hoverClick < 2) - return false; - ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(this); - // FIXME: needed only because eventdelegator registrations are done before adding node to scene graph. - if (ctx == null) - return false; - IElement e = DiagramNodeUtil.getElement(ctx, this); - if (!isEditMode()) { - if (Boolean.TRUE.equals(setEditMode(true))) { - editActivation = activateEdit(0, e, ctx); - repaint(); - } - } - } else { - hoverClick = 0; - if (isEditMode()) { - fireTextEditingEnded(); - } - } - return false; - } - - @Override - protected boolean mouseDoubleClicked(MouseDoubleClickedEvent event) { - if (event.button != MouseClickEvent.LEFT_BUTTON) - return false; - - if (hitTest(event, 0)) { - ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(this); - // FIXME: needed only because eventdelegator registrations are done before adding node to scene graph. - if (ctx == null) - return false; - - if (text != null) { - // Select the whole text. - setCaret(0, false); - setCaret(text.length(), true); - repaint(); - } - } - return false; - } - - @Override - protected boolean mouseButtonPressed(MouseButtonPressedEvent event) { - if (!isShiftDown(event)) { - return super.mouseButtonPressed(event); - } - - // Select text if shift is down. - if (!isEditMode()) - return false; - - Point2D local = controlToLocal( event.controlPosition ); - // FIXME: once the event coordinate systems are cleared up, remove this workaround - local = parentToLocal(local); - if (hover && this.containsLocal(local)) { - setCaret(local, true); - } - return false; - } - - @Override - protected boolean mouseDragged(MouseDragBegin e) { - // Disable dragging if LockSketch is ON - if (SysdynElementHints.LOCK_TOOL.equals(SysdynWorkbenchUtils.getSysdynToolMode())){ - super.mouseDragged(e); - return true;} - else - return super.mouseDragged(e); - } - - public TextEditActivation activateEdit(int mouseId, IElement e, ICanvasContext ctx, boolean save) { - if (save) - return editActivation = super.activateEdit(mouseId, e, ctx); - return super.activateEdit(mouseId, e, ctx); - } -} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/InputFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/InputFactory.java index 859dd109..7f0aca6a 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/InputFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/InputFactory.java @@ -26,6 +26,7 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.exception.MissingVariableException; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; import org.simantics.diagram.elements.TextNode; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.ui.DiagramModelHints; @@ -38,7 +39,6 @@ import org.simantics.g2d.element.SceneGraphNodeKey; import org.simantics.g2d.element.handler.InternalSize; import org.simantics.g2d.element.handler.impl.BoundsOutline; import org.simantics.g2d.element.handler.impl.DefaultTransform; -import org.simantics.g2d.element.handler.impl.HoverImpl; import org.simantics.g2d.element.handler.impl.ObjectTerminal; import org.simantics.g2d.element.handler.impl.OutlinePick; import org.simantics.g2d.element.handler.impl.SimpleElementLayers; @@ -92,7 +92,8 @@ public class InputFactory extends SysdynElementFactory { Input.INSTANCE, new InputSceneGraph(0, 0, Alignment.LEADING, 0, 1.5, 1.5, true), BoundsOutline.INSTANCE, - HoverImpl.INSTANCE, + ResizeRectangularSceneGraph.INSTANCE, + RESIZE_PROPERTY_SETTER, new WholeElementTerminals(terminals) ).setId(InputFactory.class.getSimpleName()); } @@ -165,11 +166,10 @@ public class InputFactory extends SysdynElementFactory { Font font = ElementUtils.getTextFont(e); font = font.deriveFont(font.getStyle()); ElementUtils.setTextFont(e, font); - ElementUtils.setHover(e, false); } - public static class InputSceneGraph extends HoverTextElementNoBounds implements InternalSize { + public static class InputSceneGraph extends SysdynTextElementNoBounds implements InternalSize { private static final long serialVersionUID = -3713275157729126409L; public static final Key INPUT_SG_NODE = new SceneGraphNodeKey(TextNode.class, "INPUT_SG_NODE"); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/LoopFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/LoopFactory.java index 8ea6915f..e8f11057 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/LoopFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/LoopFactory.java @@ -235,7 +235,7 @@ public class LoopFactory extends SysdynElementFactory { * @author Tuomas Miettinen * */ - public static class LoopSceneGraph extends HoverTextElementNoBounds implements HandleMouseEvent { + public static class LoopSceneGraph extends SysdynTextElementNoBounds implements HandleMouseEvent { private static final long serialVersionUID = -5093461687773246286L; @@ -286,7 +286,7 @@ public class LoopFactory extends SysdynElementFactory { } @Override - protected Callback getCallback(final IElement e, G2DParentNode parent, Class nodeClass) { + protected Callback getCallback(final IElement e, G2DParentNode parent, Class nodeClass) { return new Callback() { @Override public void run(T node) { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleFactory.java index a7f9b15f..be30fe1f 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleFactory.java @@ -18,6 +18,8 @@ import java.awt.geom.Rectangle2D; import java.util.Collection; import org.simantics.db.Resource; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; +import org.simantics.diagram.elements.TextNode; import org.simantics.g2d.element.ElementClass; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; @@ -59,12 +61,14 @@ public class ModuleFactory extends SysdynElementFactory { new ModuleSceneGraph(0, 0, Alignment.LEADING, 1f , 2, 3, true), BoundsOutline.INSTANCE, new BorderColorImpl(Color.BLACK), + ResizeRectangularSceneGraph.INSTANCE, + RESIZE_PROPERTY_SETTER, new WholeElementTerminals(terminals) ).setId(ModuleFactory.class.getSimpleName()); } - public static class ModuleSceneGraph extends HoverTextElementHandler implements InternalSize { + public static class ModuleSceneGraph extends SysdynTextElementHandler implements InternalSize { private static final long serialVersionUID = 2367230056477661273L; @@ -73,14 +77,11 @@ public class ModuleFactory extends SysdynElementFactory { super(originX, originY, horizontalAlignment, borderWidth, paddingX, paddingY, editable); } - @Override - public void init(IElement e, G2DParentNode parent) { - super.init(e, parent); - unflipText(e); - } - protected HoverTextNode getTextNode(IElement e, G2DParentNode parent) { - return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", ModuleNode.class, getCallback(e, parent, ModuleNode.class)); + + @Override + protected TextNode getOrCreateTextNode(IElement e, G2DParentNode parent) { + return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", ModuleNode.class, getCallback(e, parent, ModuleNode.class)); } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleNode.java index fa843919..73afad88 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleNode.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ModuleNode.java @@ -16,14 +16,13 @@ import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import org.simantics.scenegraph.utils.GeometryUtils; import org.simantics.scenegraph.utils.NodeUtil; -public class ModuleNode extends HoverTextNode { +public class ModuleNode extends SysdynTextNode { private static final long serialVersionUID = 8535695797227320496L; private static double CORNER_LENGTH = 2.0; @@ -34,15 +33,10 @@ public class ModuleNode extends HoverTextNode { public void render(Graphics2D g) { super.render(g); - AffineTransform ot = g.getTransform(); BasicStroke oldStroke = (BasicStroke)g.getStroke(); Color oldColor = g.getColor(); - g.transform(transform); - // Apply separate legacy scale - - - Rectangle2D bounds = expandBounds( getTightAlignedBoundsInLocal( tempBounds.get() ) ); + Rectangle2D bounds = getBounds(); Path2D path = new Path2D.Double(); @@ -66,7 +60,6 @@ public class ModuleNode extends HoverTextNode { path.lineTo(bounds.getMaxX() + CORNER_PADDING, bounds.getMaxY() + CORNER_PADDING); path.lineTo(bounds.getMaxX() + CORNER_PADDING, bounds.getMaxY() - CORNER_LENGTH); - g.translate(x, y); g.setStroke(new BasicStroke((float) (/*scale**/scale*borderWidth))); g.setColor(borderColor); g.draw(path); @@ -87,16 +80,12 @@ public class ModuleNode extends HoverTextNode { } g.setStroke(new BasicStroke(bw)); g.draw(path); - //g.draw(GeometryUtils.expandRectangle(r, 1.0)); g.setComposite(oc); } g.setColor(oldColor); g.setStroke(oldStroke); - g.translate(-x, -y); - - g.setTransform(ot); } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElement.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElement.java deleted file mode 100644 index f71c4206..00000000 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElement.java +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2012 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.sysdyn.ui.elements; - -import java.awt.Color; -import java.awt.Font; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - -import org.simantics.diagram.elements.TextElementNoBounds; -import org.simantics.diagram.elements.TextNode; -import org.simantics.g2d.element.ElementHints; -import org.simantics.g2d.element.ElementUtils; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.utils.Alignment; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.utils.datastructures.hints.IHintContext.Key; -import org.simantics.utils.datastructures.hints.IHintListener; -import org.simantics.utils.datastructures.hints.IHintObservable; - -/** - * Multi-line text element - * - * @author Teemu Lempinen - * - */ -public class MultilineTextElement extends TextElementNoBounds { - - public MultilineTextElement(double originX, double originY, Alignment horizontalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable) { - super(originX, originX, horizontalAlignment, borderWidth, paddingX, paddingY, editable); - } - - private static final long serialVersionUID = -8558567466321214111L; - - @Override - public void init(final IElement e, G2DParentNode parent) { - MultilineTextNode node = e.getHint(SG_NODE); - if(node == null) { - node = parent.addNode(MultilineTextNode.class); - e.setHint(SG_NODE, node); - } - - Font font = ElementUtils.getTextFont(e); - Color color = ElementUtils.getTextColor(e); - Color fillColor = ElementUtils.getFillColor(e); - Color borderColor = ElementUtils.getBorderColor(e, Color.GRAY); - String text = ElementUtils.getText(e); - AffineTransform at = ElementUtils.getTransform(e); - Alignment hAlign = ElementUtils.getHintOrDefault(e, ElementHints.KEY_HORIZONTAL_ALIGN, horizontalAlignment); - node.init(text, font, color, originX, originY, 0.235); - node.setBackgroundColor(fillColor); - node.setBorderColor(borderColor); - node.setHorizontalAlignment((byte) hAlign.ordinal()); - node.setPadding(paddingX, paddingY); - node.setBorderWidth((float) 1); - node.setEditable(false); // Multiline text fields are not editable - - Rectangle2D bounds = ElementUtils.getElementBounds(e); - node.setBounds(new Rectangle2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight())); // Multiline text fields have fixed bounds - if(at != null) - node.setTransform(at); - } - -} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElementFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElementFactory.java index b63810ec..d6b56d0a 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElementFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextElementFactory.java @@ -11,40 +11,14 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.elements; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; -import org.simantics.diagram.G2DUtils; import org.simantics.diagram.adapter.TextElementClassFactory; -import org.simantics.diagram.elements.ElementPropertySetter; -import org.simantics.diagram.elements.ResizeRectangularSceneGraph; -import org.simantics.diagram.stubs.DiagramResource; -import org.simantics.diagram.stubs.G2DResource; -import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.IDiagram; -import org.simantics.g2d.element.ElementClass; import org.simantics.g2d.element.ElementHints; -import org.simantics.g2d.element.ElementHints.Properties; -import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.handler.Text; -import org.simantics.g2d.element.handler.impl.BoundsOutline; -import org.simantics.g2d.element.handler.impl.DefaultTransform; -import org.simantics.g2d.element.handler.impl.OutlinePick; -import org.simantics.g2d.element.handler.impl.SimpleElementLayers; -import org.simantics.g2d.element.handler.impl.StaticObjectAdapter; -import org.simantics.g2d.element.handler.impl.StaticSymbolImpl; -import org.simantics.g2d.element.handler.impl.TextColorImpl; -import org.simantics.g2d.element.handler.impl.TextFontImpl; -import org.simantics.g2d.image.DefaultImages; -import org.simantics.g2d.image.Image; -import org.simantics.g2d.svg.SVGImage; -import org.simantics.g2d.utils.Alignment; /** * Multi-line text element used in comment in sysdyn diagrams @@ -53,74 +27,10 @@ import org.simantics.g2d.utils.Alignment; */ public class MultilineTextElementFactory extends TextElementClassFactory { - private static final Size SIZE = new Size(new Rectangle2D.Double(0, 0, 17, 7)); - private static final MultilineTextElement ELEMENT = new MultilineTextElement(0, 0, Alignment.LEADING, 1, 1.8, 1.8, false); - private static final ElementPropertySetter RESIZE_PROPERTY_SETTER = - new ElementPropertySetter(ResizeRectangularSceneGraph.KEY_SG_NODE); - - @Override - public ElementClass create(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType) throws DatabaseException { - String id = "MultilineTextElement: " + NameUtils.getSafeName(graph, elementType); - G2DResource g2d = G2DResource.getInstance(graph); - String svgDoc = graph.getPossibleRelatedValue(elementType, g2d.HasSVGDocument); - Image image = null; - if (svgDoc != null) - image = new SVGImage(id+".svg", svgDoc); - else - image = DefaultImages.ERROR_DECORATOR.get(); - return ElementClass.compile( - Text.INSTANCE, - TextColorImpl.BLACK, - TextFontImpl.DEFAULT, - new StaticObjectAdapter(elementType), - DefaultTransform.INSTANCE, - SimpleElementLayers.INSTANCE, - new StaticSymbolImpl(image), - - ELEMENT, // Changes to TextElementClassFactory start from here - SIZE, - ResizeRectangularSceneGraph.INSTANCE, - RESIZE_PROPERTY_SETTER, - BoundsOutline.INSTANCE, - OutlinePick.INSTANCE// To here - ).setId(id); - } - - @Override - public void load(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource element, IElement e) throws DatabaseException { + public void load(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource element, IElement e) + throws DatabaseException { super.load(graph, canvas, diagram, element, e); - - ElementPropertySetter ps = e.getElementClass().getSingleItem( - ElementPropertySetter.class); - ps.loadProperties(e, element, graph); - - // Set some hints.. (In future these should be removed) - Properties properties = e.getHint(ElementHints.KEY_ELEMENT_PROPERTIES); - if (properties.containsKey("Bounds")) { - e.setHint(ElementHints.KEY_BOUNDS, - (Rectangle2D) properties.get("Bounds")); - } - - // Hack for disabling all rotations in chart elements - AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, element); - double x = at.getTranslateX(); - double y = at.getTranslateY(); - at.setToRotation(0); - at.setToTranslation(x, y); - ElementUtils.setTransform(e, at); // Set hint transform without rotations - ps.overrideProperty(e, "Transform", at); // Set property Transform without rotations - - DiagramResource DIA = DiagramResource.getInstance(graph); - G2DResource G2D = G2DResource.getInstance(graph); - if (graph.isInstanceOf(element, DIA.ColorProvider)) { - Resource colorResource = graph.getPossibleObject(element, - G2D.HasColor); - if (colorResource != null) - ElementUtils.setTextColor(e, - G2DUtils.getColor(graph, colorResource)); - } + e.setHint(ElementHints.KEY_RESIZABLE, true); } - - } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextNode.java deleted file mode 100644 index 4b27ba0f..00000000 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/MultilineTextNode.java +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2012 Association for Decentralized Information Management in - * Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.sysdyn.ui.elements; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.font.LineBreakMeasurer; -import java.awt.font.TextAttribute; -import java.awt.font.TextLayout; -import java.awt.geom.Rectangle2D; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; -import java.util.ArrayList; -import java.util.Hashtable; - -import org.simantics.diagram.elements.TextNode; -import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin; -import org.simantics.scenegraph.utils.GeometryUtils; -import org.simantics.scenegraph.utils.NodeUtil; -import org.simantics.sysdyn.ui.utils.SysdynWorkbenchUtils; - -/** - * Multi-line text node for diagrams. Editing is not - * implemented yet. - * - * @author Teemu Lempinen - * - */ -public class MultilineTextNode extends TextNode { - - protected PositionedText[] precomputedLayout; - protected Rectangle2D bounds; - - /** - * Auxiliary class for drawing positioned text - * @author Teemu Lempinen - * - */ - class PositionedText { - float drawPosX; - float drawPosY; - TextLayout layout; - - public PositionedText(float drawPosX, float drawPosY, TextLayout layout) { - this.drawPosX = drawPosX; - this.drawPosY = drawPosY; - this.layout = layout; - } - - public void render(Graphics2D g) { - layout.draw(g, drawPosX, drawPosY); - } - } - - private static final long serialVersionUID = -1900821098537908613L; - - @SyncField({ "bounds" }) - public void setBounds(Rectangle2D bounds) { - this.bounds = bounds; - } - - @Override - public void init(String text, Font font, Color color, double x, double y, double scale) { - super.init(text, font, color, x, y, scale); - resetPrecompudedLayout(); - } - - @Override - public void setText(String text) { - super.setText(text); - resetPrecompudedLayout(); - } - - @Override - public void setFont(Font font) { - super.setFont(font); - resetPrecompudedLayout(); - } - - @Override - public void setHover(boolean hover) { - super.setHover(hover); - resetPrecompudedLayout(); - } - - /** - * Reset layout cache - */ - private void resetPrecompudedLayout() { - precomputedLayout = null; - } - - /** - * Compute layout for multi-row text - * @param g Graphics2D - * @param color Font color - */ - private void precomputeLayout(Graphics2D g, Color color) { - ArrayList precomputedLayout = - new ArrayList(); - - Hashtable map = new Hashtable(); - - map.put(TextAttribute.FONT, font); - map.put(TextAttribute.FOREGROUND, color); - - AttributedString attributedText = new AttributedString(text.isEmpty() ? "__ERROR__" : text, map); - - AttributedCharacterIterator paragraph = attributedText.getIterator(); - int paragraphStart = paragraph.getBeginIndex(); - int paragraphEnd = paragraph.getEndIndex(); - LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, FRC); - - if(bounds == null) { - System.err.println("bounds==null in MultilineTextNode"); - return; - } - - float textAreaWidth = (float) scaleRecip * ((float) bounds.getWidth() - 2 * (float) paddingX); - float breakWidth = textAreaWidth; - - // Force text to be vertical, by setting break width to 1, if the text area is narrower than "GGGG" - FontMetrics fm = g.getFontMetrics(font); - Rectangle2D stringBounds = fm.getStringBounds(text, g); - Rectangle2D lowerLimitBounds = fm.getStringBounds("GGGG", g); - if(breakWidth < stringBounds.getWidth() && breakWidth < lowerLimitBounds.getWidth()) - breakWidth = 1; - - // Maximum height - float breakHeight = (float) scaleRecip * ((float) bounds.getHeight() - 2 * (float) paddingY); - - if(breakWidth <= 0 || breakHeight <= 0) { - return; - } - - float drawPosY = 0; - // Set position to the index of the first character in the paragraph. - lineMeasurer.setPosition(paragraphStart); - - // Get lines until the entire paragraph has been displayed. - int next, limit, charat, position = 0; - while ((position = lineMeasurer.getPosition()) < paragraphEnd) { - - // Find possible line break and set it as a limit to the next layout - next = lineMeasurer.nextOffset(breakWidth); - limit = next; - charat = text.indexOf(System.getProperty("line.separator"),position+1); - if(charat < next && charat != -1){ - limit = charat; - } - - // Retrieve next layout. A cleverer program would also cache - // these layouts until the component is re-sized. - TextLayout layout = lineMeasurer.nextLayout(breakWidth, limit, false); - - // Compute pen x position. If the paragraph is right-to-left we - // will align the TextLayouts to the right edge of the panel. - // Note: this won't occur for the English text in this sample. - // Note: drawPosX is always where the LEFT of the text is placed. - float drawPosX = layout.isLeftToRight() ? 0 : breakWidth - - layout.getAdvance(); - - // If text has been forced to vertical, align it to center - if(breakWidth < textAreaWidth) { - float centerCorrection = layout.isLeftToRight() ? - (float) (layout.getAdvance() / 2) : - -1 * (float) (layout.getAdvance() / 2); - drawPosX = textAreaWidth / 2 - centerCorrection; - } - - // Stop drawing if the text won't fit - if (breakHeight < drawPosY + layout.getDescent() - + layout.getLeading()) { - break; - } - - drawPosY += layout.getAscent(); - - // Add TextLayout at (drawPosX, drawPosY). - precomputedLayout.add(new PositionedText(drawPosX, drawPosY, layout)); - - // Move y-coordinate in preparation for next layout. - drawPosY += layout.getDescent() + layout.getLeading(); - } - - this.precomputedLayout = - precomputedLayout.toArray(new PositionedText[precomputedLayout.size()]); - } - - public void render(Graphics2D g, boolean applyTransform) { - if (text == null || font == null || color == null) - return; - - double horizontalAlignOffset = getHorizontalAlignOffset(bounds); - double verticalAlignOffset = getVerticalAlignOffset(); - - Color color = this.color; - - boolean isSelected = NodeUtil.isSelected(this, 1); - - if (!isSelected && hover) { - color = add(color, 120, 120, 120); - } - - if (applyTransform) - g.transform(transform); - - g.scale(scale, scale); - g.translate(horizontalAlignOffset, verticalAlignOffset); - - Rectangle2D r = new Rectangle2D.Double(bounds.getX() , bounds.getY(), bounds.getWidth() * scaleRecip, bounds.getHeight() * scaleRecip); - // Draw border if necessary - if (borderWidth > 0.f) { - g.setColor(borderColor); - g.setStroke(new BasicStroke((float) (scale*borderWidth))); -// g.draw(r); Borders are disabled for now - } - - // Fill background if necessary - if (backgroundColor != null) { - g.setColor(backgroundColor); - g.fill(r); - } - - if (isSelected && showsSelection()) { - Composite oc = g.getComposite(); - g.setComposite(AlphaComposite.SrcAtop.derive(0.5f)); - - g.setColor(Color.RED); - float bw = borderWidth; - double s = GeometryUtils.getScale(g.getTransform()); - if (bw <= 0f) { - bw = (float) (1f / s); - } else { - bw *= 5f * scale; - } - g.setStroke(new BasicStroke(bw)); - g.draw(r); - - g.setComposite(oc); - } - - g.setFont(font); - - // Draw text - g.translate(x + paddingX * (float) scaleRecip, y + paddingY * (float) scaleRecip); - if(precomputedLayout == null) { - precomputeLayout(g, color); - if(precomputedLayout == null) - return; - } - - for(PositionedText text : precomputedLayout) - text.render(g); - - - g.setStroke(new BasicStroke(1)); - - g.translate(-horizontalAlignOffset, -verticalAlignOffset); - g.scale(scaleRecip, scaleRecip); - - renderSelectedHover(g, isSelected, hover); - - } - - @Override - protected boolean mouseDragged(MouseDragBegin e) { - // Disable dragging if LockSketch is ON - if (SysdynElementHints.LOCK_TOOL.equals(SysdynWorkbenchUtils.getSysdynToolMode())) - return false; - else - return super.mouseDragged(e); - } - -} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ShadowFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ShadowFactory.java index 6e310e19..726cae6f 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ShadowFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ShadowFactory.java @@ -21,6 +21,8 @@ import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; +import org.simantics.diagram.elements.TextElementHandler; import org.simantics.diagram.synchronization.SynchronizationHints; import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; import org.simantics.g2d.canvas.ICanvasContext; @@ -49,7 +51,7 @@ import org.simantics.sysdyn.SysdynResource; public class ShadowFactory extends SysdynElementFactory { - private static HoverTextElementHandler shadowHandler = new HoverTextElementHandler(0, 0, Alignment.LEADING, 0.0, 2.0, 2.0, false); + private static TextElementHandler shadowHandler = new TextElementHandler(0, 0, Alignment.LEADING, 0.0, 2.0, 2.0, false); private static final TextColorImpl GRAY = new TextColorImpl(java.awt.Color.GRAY); private static final BasicStroke STROKE = new BasicStroke(1f); public static final Image GHOST_IMAGE = new ShapeImage(getGhostShape(), null, STROKE, true); @@ -90,6 +92,8 @@ public class ShadowFactory extends SysdynElementFactory { StaticSymbolImageInitializer.INSTANCE, shadowHandler, BoundsOutline.INSTANCE, + ResizeRectangularSceneGraph.INSTANCE, + RESIZE_PROPERTY_SETTER, new WholeElementTerminals(terminals) ).setId(ShadowFactory.class.getSimpleName()); } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockFactory.java index 13a6ee48..a821104c 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/StockFactory.java @@ -19,6 +19,7 @@ import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.element.ElementClass; @@ -39,7 +40,6 @@ import org.simantics.g2d.element.handler.impl.TextImpl; import org.simantics.g2d.image.Image; import org.simantics.g2d.image.impl.ShapeImage; import org.simantics.g2d.utils.Alignment; -import org.simantics.scenegraph.g2d.G2DParentNode; public class StockFactory extends SysdynElementFactory { @@ -58,9 +58,11 @@ public class StockFactory extends SysdynElementFactory { new StaticObjectAdapter(elementType), new StaticSymbolImpl(STOCK_IMAGE), StaticSymbolImageInitializer.INSTANCE, - new StockSceneGraph(0, 0, Alignment.LEADING, 1f, 1.0, 1.0, true), + new SysdynTextElementHandler(0, 0, Alignment.LEADING, 1f, 1.0, 1.0, true), BoundsOutline.INSTANCE, new BorderColorImpl(Color.BLACK), + ResizeRectangularSceneGraph.INSTANCE, + RESIZE_PROPERTY_SETTER, new WholeElementTerminals(terminals) ).setId(StockFactory.class.getSimpleName()); } @@ -70,23 +72,5 @@ public class StockFactory extends SysdynElementFactory { super.load(graph, canvas, diagram, element, e); e.setHint(ElementHints.KEY_BORDER_COLOR, e.getHint(ElementHints.KEY_TEXT_COLOR)); } - - public static class StockSceneGraph extends HoverTextElementHandler { - - private static final long serialVersionUID = 6635538659448488606L; - - public StockSceneGraph(double i, double j, Alignment leading, double k, double d, - double e, boolean b) { - super(i, j, leading, k, d, e, b); - } - - @Override - public void init(IElement e, G2DParentNode parent) { - super.init(e, parent); - unflipText(e); - } - - } - } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynElementFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynElementFactory.java index 6f7c9043..174ae574 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynElementFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynElementFactory.java @@ -14,6 +14,7 @@ package org.simantics.sysdyn.ui.elements; import java.awt.Color; import java.awt.Font; import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -32,6 +33,8 @@ import org.simantics.db.exception.ServiceException; import org.simantics.diagram.G2DUtils; import org.simantics.diagram.adapter.SyncElementFactory; import org.simantics.diagram.content.ResourceTerminal; +import org.simantics.diagram.elements.ElementPropertySetter; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.stubs.G2DResource; import org.simantics.diagram.synchronization.CompositeHintSynchronizer; @@ -66,6 +69,9 @@ public abstract class SysdynElementFactory extends SyncElementFactory { ComponentNameSynchronizer.INSTANCE, TransformSynchronizer.INSTANCE); + public static final ElementPropertySetter RESIZE_PROPERTY_SETTER = + new ElementPropertySetter(ResizeRectangularSceneGraph.KEY_SG_NODE); + protected String getText(ReadGraph graph, Resource element) throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); ModelingResources mr = ModelingResources.getInstance(graph); @@ -81,6 +87,7 @@ public abstract class SysdynElementFactory extends SyncElementFactory { @Override public void load(ReadGraph graph, final ICanvasContext canvas, final IDiagram diagram, final Resource element, final IElement e) throws DatabaseException { + e.setHint(ElementHints.KEY_RESIZABLE, true); ElementUtils.setText(e, getText(graph, element)); // Just testing loop finding. //ModelingResources mr = ModelingResources.getInstance(graph); @@ -153,6 +160,11 @@ public abstract class SysdynElementFactory extends SyncElementFactory { font = font.deriveFont(Font.BOLD); ElementUtils.setTextFont(e, font); } + + double bounds[] = DiagramGraphUtil.getPossibleRelatedDoubleArray(graph, element, G2DResource.getInstance(graph).HasBounds); + if (bounds != null) { + e.setHint(ElementHints.KEY_BOUNDS, new Rectangle2D.Double(bounds[0], bounds[1], bounds[2], bounds[3])); + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementHandler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementHandler.java new file mode 100644 index 00000000..408ff09b --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementHandler.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT - initial API and implementation + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.elements; + +import java.awt.geom.Rectangle2D; + +import org.simantics.diagram.elements.TextElementHandler; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.InternalSize; +import org.simantics.g2d.utils.Alignment; + +/** + * Version of {@link SysdynTextElementNoBounds} that supports InternalSize + * @author Teemu Lempinen + * + */ +public class SysdynTextElementHandler extends SysdynTextElementNoBounds implements InternalSize { + private static final long serialVersionUID = -1307413505370441178L; + + public static SysdynTextElementHandler INSTANCE = new SysdynTextElementHandler(); + + public SysdynTextElementHandler() { + super(); + } + + public SysdynTextElementHandler(double originX, double originY, Alignment horizontalAlignment) { + super(originX, originY, horizontalAlignment); + } + + public SysdynTextElementHandler(double originX, double originY, Alignment horizontalAlignment, double borderWidth) { + super(originX, originY, horizontalAlignment, borderWidth); + } + + public SysdynTextElementHandler(double originX, double originY, Alignment horizontalAlignment, double borderWidth, + double paddingX, double paddingY, boolean editable) { + super(originX, originY, horizontalAlignment, borderWidth, paddingX, paddingY, editable); + } + + @Override + public Rectangle2D getBounds(IElement e, Rectangle2D size) { + Rectangle2D bounds = TextElementHandler.calculateBounds(e, size, horizontalAlignment, SCALE, paddingX, paddingX); + return bounds; + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementNoBounds.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementNoBounds.java new file mode 100644 index 00000000..76defa5b --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextElementNoBounds.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT - initial API and implementation + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.elements; + +import java.awt.Color; +import java.awt.geom.AffineTransform; + +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IWorkbenchPage; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.elements.DiagramNodeUtil; +import org.simantics.diagram.elements.ITextListener; +import org.simantics.diagram.elements.TextElementNoBounds; +import org.simantics.diagram.elements.TextNode; +import org.simantics.diagram.participant.SGFocusParticipant; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.chassis.SWTChassis; +import org.simantics.g2d.diagram.DiagramUtils; +import org.simantics.g2d.diagram.IDiagram; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.utils.Alignment; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.modeling.ui.diagramEditor.DiagramEditor; +import org.simantics.modeling.ui.diagramEditor.DiagramViewer; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.sysdyn.SysdynResource; +import org.simantics.sysdyn.ui.utils.SysdynWorkbenchUtils; +import org.simantics.sysdyn.ui.utils.VariableNameValidator; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.datastructures.Callback; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; + +/** + * TextElement for variables in Siamntics System Dynamics + * + * The main differences for the basic TextElementNoBounds are: + * 1. Text is never mirrored + * 2. Edit mode is activated when the variable is created + * + * @author Teemu Lempinen + * + */ +public class SysdynTextElementNoBounds extends TextElementNoBounds { + + private static final long serialVersionUID = -148784588840819612L; + + public static final Key ELEMENT_INITIALIZED = new KeyOf(Boolean.class, "SYSDYN_TEXT_ELEMENT_INITIALIZED"); + + // Constructors + public SysdynTextElementNoBounds() { + super(0, 0, Alignment.LEADING, 0); + } + + public SysdynTextElementNoBounds(double originX, double originY, Alignment horizontalAlignment) { + super(originX, originY, horizontalAlignment, 0); + } + + public SysdynTextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth) { + super(originX, originY, horizontalAlignment, borderWidth); + } + + public SysdynTextElementNoBounds(double originX, double originY, Alignment horizontalAlignment, double borderWidth, double paddingX, double paddingY, boolean editable) { + super(originX, originY, horizontalAlignment, borderWidth, paddingX, paddingY, editable); + } + + // End constructors + + protected Callback getCallback(final IElement e, G2DParentNode parent, Class nodeClass) { + return new Callback() { + @Override + public void run(T node) { + node.setTextListener(new ITextListener() { + + String textBeforeEdit; + Resource component; + + @Override + public void textChanged() { + TextNode node = (TextNode) e.getHint(SG_NODE); + if(!new VariableNameValidator().isValid(component, node.getText(), false)) { + node.setColor(Color.RED); + } else { + node.setColor(ElementUtils.getTextColor(e, Color.BLACK)); + } + + + } + + @Override + public void textEditingStarted() { + TextNode node = (TextNode) e.getHint(SG_NODE); + textBeforeEdit = node.getText(); + + if(component != null) return; + + Object o = e.getHint(ElementHints.KEY_OBJECT); + if(o != null && o instanceof Resource) { + final Resource element = (Resource)o; + SimanticsUI.getSession().asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + component = graph.getPossibleObject(element, ModelingResources.getInstance(graph).ElementToComponent); + } + }); + } + } + + @Override + public void textEditingCancelled() { + TextNode node = (TextNode) e.getHint(SG_NODE); + if (node != null) { + if(new VariableNameValidator().isValid(component, node.getText(), false)) + node.setColor(ElementUtils.getTextColor(e, Color.BLACK)); + endEdit(node); + } + } + + @Override + public void textEditingEnded() { + TextNode node = (TextNode) e.getHint(SG_NODE); + if (node == null) + return; + String text = node.getText(); + if(!new VariableNameValidator().isValid(component, text, false)) { + text = textBeforeEdit; + node.setText(text); + if(new VariableNameValidator().isValid(component, text, false)) + node.setColor(ElementUtils.getTextColor(e, Color.BLACK)); + } else { + Object o = e.getHint(ElementHints.KEY_OBJECT); + final String textAfterEdit = text; + if(o != null && o instanceof Resource) { + SimanticsUI.getSession().asyncRequest(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Resource configuration = graph.getPossibleObject(component, Layer0.getInstance(graph).PartOf); + new VariableNameValidator().renameInAllEquations(graph, configuration, textBeforeEdit, textAfterEdit); + } + }); + } + } + ElementUtils.setText(e, text); + IDiagram diagram = ElementUtils.getDiagram(e); + DiagramUtils.synchronizeHintsToBackend(diagram, e); + endEdit(node); + } + }); + } + }; + } + + /** + * Reverts any rotations that are assigned to the text element + * @param e + */ + public static void unflipText(IElement e) { + Object o = e.getHint(SG_NODE); + if (o instanceof TextNode) { + TextNode text = (TextNode)o; + AffineTransform at = text.getTransform(); + double x = at.getTranslateX(); + double y = at.getTranslateY(); + at.setToRotation(0); + at.setToTranslation(x, y); + at.setTransform(at); + } + } + + /** + * Activates edit mode for a newly created variable. + * + * Sets focus for diagram if the variable was created by dragging from model browser. + * + * @param e + */ + protected void activateEdit(final IElement e) { + final SysdynTextNode node = e.getHint(SG_NODE); + if(node == null) + return; + + final ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node); + // FIXME: needed only because eventdelegator registrations are done before adding node to scene graph. + if (ctx == null) + return; + if (!node.isEditMode()) { + + // Get the active editor + IWorkbenchPage page = SysdynWorkbenchUtils.getActivePageOfEditor(); + final DiagramEditor editor = (DiagramEditor)page.getActiveEditor(); + final ICanvasContext editorCtx = (ICanvasContext) editor.getViewer().getAdapter(ICanvasContext.class); + + editor.getViewer().getComposite().getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + Control c = editor.getViewer().getComposite().getDisplay().getFocusControl(); + if (c == null || "BasicSymbols".equals(c.getParent().getToolTipText())) { + // If the variable has been drag and dropped, set focus to diagram and then activate edit. + + editorCtx.add(new SGFocusParticipant((SWTChassis)editor.getViewer().getComposite(), DiagramViewer.DIAGRAMMING_CONTEXT) { + + @Override + public void focusGained(java.awt.event.FocusEvent event) { + + // When focus has been gained, acticate edit and destroy the listener. + editor.getViewer().getComposite().getDisplay().asyncExec(new Runnable() { + + @Override + public void run() { + if (Boolean.TRUE.equals(node.setEditMode(true))) { + node.activateEdit(0, e, ctx, true); + node.repaint(); + } + } + }); + ctx.remove(this); + } + + @Override + public void focusLost(java.awt.event.FocusEvent e) { + } + }); + + editor.setFocus(); + } else { + // If the variable has been created with shortcut key, just activate the edit. + if (Boolean.TRUE.equals(node.setEditMode(true))) { + node.activateEdit(0, e, ctx, true); + node.repaint(); + } + } + } + }); + } + } + + @Override + protected TextNode getOrCreateTextNode(IElement e, G2DParentNode parent) { + return ElementUtils.getOrCreateNode(e, parent, SG_NODE, "text", SysdynTextNode.class, getCallback(e, parent, SysdynTextNode.class)); + } + + @Override + public void init(final IElement e, G2DParentNode parent) { + super.init(e, parent); + + + // Add handling for activating text edit for new variables + // Store initialization status to hints to prevent unnecessary graph queries + Boolean isInitialized = e.getHint(ELEMENT_INITIALIZED); + Object o = e.getHint(ElementHints.KEY_OBJECT); + if (o instanceof Resource && !Boolean.TRUE.equals(isInitialized)) { + final Resource element = (Resource)o; + try { + SimanticsUI.getSession().syncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + SysdynResource SR = SysdynResource.getInstance(graph); + ModelingResources MR = ModelingResources.getInstance(graph); + Resource component = graph.getPossibleObject(element, MR.ElementToComponent); + if (component == null) + return; + + // See if the resource of the element has just been created. + Resource r = graph.getPossibleObject(component, SR.IndependentVariable_isUninitialized); + if (r == null){ + return; + } + + // If the resource is just been created, activate editing its name. + if (!graph.isInstanceOf(r, SR.Loop)) { + activateEdit(e); + } + graph.deny(component, SR.IndependentVariable_isUninitialized, r); + } + }); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + e.setHint(ELEMENT_INITIALIZED, Boolean.TRUE); + } + + unflipText(e); + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextNode.java new file mode 100644 index 00000000..03301917 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/SysdynTextNode.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT - initial API and implementation + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.elements; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; + +import org.simantics.diagram.elements.TextEditActivation; +import org.simantics.diagram.elements.TextNode; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.element.IElement; +import org.simantics.scenegraph.g2d.events.EventTypes; +import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin; +import org.simantics.sysdyn.ui.utils.SysdynWorkbenchUtils; + +/** + * Text node for Sysdyn elements. + * + * Additions to the basic node: + * 1. Draw borders when hovering + * 2. Support Sysdyn's diagram locking + * @author Teemu Lempinen + * + */ +public class SysdynTextNode extends TextNode { + + private static final long serialVersionUID = 5235077104121753251L; + + + @Override + public int getEventMask(){ + return EventTypes.FocusLostMask | super.getEventMask(); + } + + @Override + protected boolean mouseDragged(MouseDragBegin e) { + // Disable dragging if LockSketch is ON + if (SysdynElementHints.LOCK_TOOL.equals(SysdynWorkbenchUtils.getSysdynToolMode())){ + super.mouseDragged(e); + return true;} + else + return super.mouseDragged(e); + } + + + @Override + protected void renderSelectedHover(Graphics2D g, boolean isSelected, boolean isHovering) { + + if (!isSelected && isHovering) { + BasicStroke oldStroke = (BasicStroke)g.getStroke(); + Color oldColor = g.getColor(); + g.setColor(Color.LIGHT_GRAY); + g.setStroke(new BasicStroke((float)(2.0*scale))); + g.draw(getBoundsInLocal()); + g.setColor(oldColor); + g.setStroke(oldStroke); + + } + + } + + public TextEditActivation activateEdit(int mouseId, IElement e, ICanvasContext ctx, boolean save) { + if (save) + return editActivation = super.activateEdit(mouseId, e, ctx); + return super.activateEdit(mouseId, e, ctx); + } + +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java index 94d16aea..200ce9e5 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveFactory.java @@ -13,18 +13,19 @@ package org.simantics.sysdyn.ui.elements; import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Font; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; +import java.awt.Shape; import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Path2D; -import java.awt.geom.Path2D.Double; import java.awt.geom.Rectangle2D; import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.exception.DatabaseException; +import org.simantics.diagram.elements.ResizeNode.TranslateEdge; +import org.simantics.diagram.elements.ResizeRectangularSceneGraph; +import org.simantics.diagram.elements.TextElementNoBounds; import org.simantics.diagram.elements.TextNode; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.diagram.IDiagram; @@ -33,8 +34,8 @@ import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.SceneGraphNodeKey; -import org.simantics.g2d.element.handler.HandleMouseEvent; import org.simantics.g2d.element.handler.InternalSize; +import org.simantics.g2d.element.handler.SceneGraph; import org.simantics.g2d.element.handler.impl.DefaultTransform; import org.simantics.g2d.element.handler.impl.HoverImpl; import org.simantics.g2d.element.handler.impl.ObjectTerminal; @@ -83,10 +84,14 @@ public class ValveFactory extends SysdynElementFactory { new StaticSymbolImpl(VALVE_STATIC_IMAGE), StaticSymbolImageInitializer.INSTANCE, HoverImpl.INSTANCE, - ValveSceneGraph.INSTANCE, - ValveOutline.INSTANCE, Orientation.INSTANCE, ValveTextLocation.INSTANCE, + ValveSceneGraph.INSTANCE, + ValveText.INSTANCE, + new ResizeRectangularSceneGraph(TextElementNoBounds.SG_NODE), + RESIZE_PROPERTY_SETTER, + ValveBounds.INSTANCE, + ValveOutline.INSTANCE, new WholeElementTerminals(terminals) ).setId(ValveFactory.class.getSimpleName()); } @@ -120,6 +125,25 @@ public class ValveFactory extends SysdynElementFactory { } SysdynElementUtils.setValveTextLocation(e, locationText); + + ResizeRectangularSceneGraph resize = e.getElementClass().getSingleItem(ResizeRectangularSceneGraph.class); + if(resize != null) { + + if(location == null || sr.Bottom.equals(location)) { + resize.setYTranslateEdge(TranslateEdge.NORTH); + resize.setXTranslateEdge(TranslateEdge.NONE); + } else if(sr.Top.equals(location)) { + resize.setYTranslateEdge(TranslateEdge.SOUTH); + resize.setXTranslateEdge(TranslateEdge.NONE); + } else if(sr.Left.equals(location)) { + resize.setYTranslateEdge(TranslateEdge.NONE); + resize.setXTranslateEdge(TranslateEdge.EAST); + } else { + resize.setYTranslateEdge(TranslateEdge.NONE); + resize.setXTranslateEdge(TranslateEdge.WEST); + } + } + } /** @@ -142,26 +166,110 @@ public class ValveFactory extends SysdynElementFactory { path.closePath(); return path; } + + public static class ValveText extends SysdynTextElementNoBounds { + private static final long serialVersionUID = -5354779831383095960L; + + public static ValveText INSTANCE = new ValveText(); + + public ValveText() { + super(0, 0, Alignment.CENTER, 0, 1, 1, true); + } + + @Override + public void init(IElement e, G2DParentNode parent) { + super.init(e, parent); + + TextNode text = e.getHint(TextElementNoBounds.SG_NODE); + HoverShapeNode valve = e.getHint(ValveSceneGraph.VALVE_SG_NODE); + if(valve != null && text != null) { + Rectangle2D textBounds = text.getBoundsInLocal(); + Rectangle2D valveBounds = valve.getBoundsInLocal(); + AffineTransform at = (AffineTransform) text.getTransform().clone(); + at.translate( + getTextXTranslate(e, textBounds, valveBounds), + getTextYTranslate(e, textBounds, valveBounds)); + text.setTransform(at); + } + + } + + private static double getTextXTranslate(IElement e, Rectangle2D textBounds, Rectangle2D valveBounds) { + String location = e.getHint(SysdynElementHints.KEY_LOCATION); + if(location.equals("Bottom")) { + return -textBounds.getCenterX(); + } else if(location.equals("Top")) { + return -textBounds.getCenterX(); + } else if(location.equals("Left")) { + return -textBounds.getMaxX() - valveBounds.getWidth() / 2; + } else { + return valveBounds.getMaxX() - textBounds.getMinX(); + } + } + + private static double getTextYTranslate(IElement e, Rectangle2D textBounds, Rectangle2D valveBounds) { + String location = e.getHint(SysdynElementHints.KEY_LOCATION); + if(location.equals("Bottom")) { + return valveBounds.getMaxY() - textBounds.getMinY(); + } else if(location.equals("Top")) { + return valveBounds.getMinY() - textBounds.getMaxY(); + } else if(location.equals("Left")) { + return -textBounds.getCenterY(); + } else { + return -textBounds.getCenterY(); + } + } + } + + public static class ValveBounds implements InternalSize { + private static final long serialVersionUID = -666692270776359301L; - public static class ValveSceneGraph extends HoverTextElementNoBounds implements InternalSize, HandleMouseEvent { + public static final ValveBounds INSTANCE = new ValveBounds(); - private static final long serialVersionUID = 5544256245734478634L; + @Override + public Rectangle2D getBounds(IElement e, Rectangle2D size) { + TextNode textNode = e.getHint(TextElementNoBounds.SG_NODE); + ValveSceneGraph valveSG = e.getElementClass().getSingleItem(ValveSceneGraph.class); + + if(textNode != null && valveSG != null) { + try { + AffineTransform elementTransform = ElementUtils.getTransform(e); + AffineTransform nodeTransform = textNode.getTransform(); + + AffineTransform elementTransformInverse = elementTransform.createInverse(); + elementTransformInverse.concatenate(nodeTransform); + + Rectangle2D text = textNode.getBoundsInLocal(); + Shape textShape = elementTransformInverse.createTransformedShape(text); + + Rectangle2D valve = valveSG.getValveBounds(e, new Rectangle2D.Double()); + + size.setRect(textShape.getBounds2D()); + size.add(valve); + return size; + } catch (NoninvertibleTransformException e1) { + e1.printStackTrace(); + } + } + // FallBack + Path2D path = createShape(VALVE_SIZE, Boolean.TRUE.equals(e.getHint(KEY_ROTATED))); + return path.getBounds2D(); + } + + } + + public static class ValveSceneGraph implements SceneGraph { + private static final long serialVersionUID = 7987939328158347639L; public static final ValveSceneGraph INSTANCE = new ValveSceneGraph(); - private static final Key NODE = new SceneGraphNodeKey(ShapeNode.class, "VALVE_NODE"); + private static final Key VALVE_SG_NODE = new SceneGraphNodeKey(ShapeNode.class, "VALVE_SHAPE_NODE"); private IHintListener hoverHintListener; - public ValveSceneGraph() { -// super(0, VALVE_SIZE + 3.0, Alignment.CENTER); // Move with affine transformation in init() - super(0, 0, Alignment.CENTER, 0, 1, 1, true); - } @Override public void init(IElement e, G2DParentNode parent) { - super.init(e, parent); - AffineTransform at = ElementUtils.getTransform(e); - final HoverShapeNode node = ElementUtils.getOrCreateNode(e, parent, NODE, "valve", HoverShapeNode.class); + final HoverShapeNode node = ElementUtils.getOrCreateNode(e, parent, VALVE_SG_NODE, "valveShape", HoverShapeNode.class); // Calculate borders from text node bounds. node.setStroke(STROKE); @@ -175,31 +283,11 @@ public class ValveFactory extends SysdynElementFactory { node.setShape(createShape(VALVE_SIZE, Boolean.TRUE.equals(rotated))); Boolean hover = e.getHint(ElementHints.KEY_HOVER); node.setHover(hover != null ? hover : false); - - if(at != null) { + + AffineTransform at = ElementUtils.getTransform(e); + if(at != null) node.setTransform(at); - TextNode name = (TextNode) e.getHint(SG_NODE); - if(name != null) { - - AffineTransform at2 = (AffineTransform) at.clone(); - Alignment alignment = null; - - String location = e.getHint(SysdynElementHints.KEY_LOCATION); - if(location != null) { - at2.translate(getXCoordShift(e), getYCoordShift(e)); - if(location.equals("Left")) { - alignment = Alignment.TRAILING; - } else if(location.equals("Right")) { - alignment = Alignment.LEADING; - } - } - - name.setTransform(at2); - if(alignment != null) - name.setHorizontalAlignment((byte) alignment.ordinal()); - } - } hoverHintListener = new IHintListener() { @@ -211,7 +299,7 @@ public class ValveFactory extends SysdynElementFactory { @Override public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { IElement e = (IElement)sender; - HoverShapeNode shape = (HoverShapeNode) e.getHint(NODE); + HoverShapeNode shape = (HoverShapeNode) e.getHint(VALVE_SG_NODE); if(shape == null) { return; } @@ -219,194 +307,32 @@ public class ValveFactory extends SysdynElementFactory { shape.setHover(hover); } }; - e.addHintListener(hoverHintListener); - - unflipText(e); + e.addHintListener(hoverHintListener); } @Override public void cleanup(IElement e) { e.removeHintListener(hoverHintListener); - ElementUtils.removePossibleNode(e, NODE); - } - - @Override - public Rectangle2D getBounds(IElement e, Rectangle2D size) { - if (size == null) - size = new Rectangle2D.Double(); - size.setFrame(createShape(VALVE_SIZE, Boolean.TRUE.equals(e.getHint(KEY_ROTATED))).getBounds2D()); - double paddingX = 2.0; - double paddingY = 2.0; - size.setRect(size.getX() - paddingX, size.getY() -paddingY, size.getWidth() + paddingX + paddingX, size.getHeight() + paddingY + paddingY); - return size; - } - - private static double getXCoordShift(IElement e) { - String location = e.getHint(SysdynElementHints.KEY_LOCATION); - if(location.equals("Bottom")) { - return 0; - } else if(location.equals("Top")) { - return 0; - } else if(location.equals("Left")) { - return -VALVE_SIZE - 1; - } else { - return VALVE_SIZE + 1; - } + ElementUtils.removePossibleNode(e, VALVE_SG_NODE); } - private static double getYCoordShift(IElement e) { - String location = e.getHint(SysdynElementHints.KEY_LOCATION); - if(location.equals("Bottom")) { - return VALVE_SIZE + 3; - } else if(location.equals("Top")) { - return -VALVE_SIZE - 1; - } else if(location.equals("Left")) { - return 0; - } else { - return 0; - } - } - private Rectangle2D getBoundsText(IElement e, Rectangle2D size) { - HoverTextNode node = (HoverTextNode) e.getHint(SG_NODE); + public Rectangle2D getValveBounds(IElement e, Rectangle2D size) { if (size == null) size = new Rectangle2D.Double(); - if (node != null) { - Rectangle2D local = node.getBoundsInLocal(); - local.setRect(local.getX() + getXCoordShift(e), - local.getY() + getYCoordShift(e), - local.getWidth(), - local.getHeight()); - size.setRect(local); - } - else { - String text = e.getHint(ElementHints.KEY_TEXT); - Font font = e.getHint(ElementHints.KEY_FONT); - if(text == null || font == null) - size.setFrame(0, 0, 0, 0); - else { - FontRenderContext FRC = new FontRenderContext(new AffineTransform(), true, true); - TextLayout tl = new TextLayout(text, font, FRC); - Rectangle2D bounds = tl.getLogicalHighlightShape(0, text.length()).getBounds2D(); - size.setFrame( - bounds.getX() * SCALE - paddingX, - (bounds.getY() + VALVE_SIZE) * SCALE - paddingY, - bounds.getWidth()* SCALE + paddingX + paddingX, - bounds.getHeight()* SCALE + paddingY + paddingY); - } - } - return size; - } - - public Path2D.Double getBoundsPath(IElement e, Path2D.Double size) { - if (size == null) - size = new Path2D.Double(); - - // Get the rectangles for the Valve symbol and the text field. - Rectangle2D valve = getBounds(e, new Rectangle2D.Double()); - Rectangle2D text = getBoundsText(e, new Rectangle2D.Double()); - // Combine the two. - String location = e.getHint(SysdynElementHints.KEY_LOCATION); - if(location.equals("Bottom")) { - return getBoundsPathBottom(size, valve, text); - } else if(location.equals("Top")) { - return getBoundsPathTop(size, valve, text); - } else if(location.equals("Left")) { - return getBoundsPathLeft(size, valve, text); + HoverShapeNode node = e.getHint(VALVE_SG_NODE); + if(node != null) { + size.setFrame(node.getBoundsInLocal()); } else { - return getBoundsPathRight(size, valve, text); + size.setFrame(createShape(VALVE_SIZE, Boolean.TRUE.equals(e.getHint(KEY_ROTATED))).getBounds2D()); } + + // Add some padding to the valve + double padding = 1; + size.setFrame(size.getX() - padding, size.getY() - padding, size.getWidth() + padding * 2, size.getHeight() + padding * 2); + return size; } - private Double getBoundsPathBottom(Path2D.Double size, Rectangle2D valve, - Rectangle2D text) { - double xV = valve.getX(); - double xVM = valve.getMaxX(); - double yV = valve.getY(); - //double yVM = valve.getMaxY(); - double xT = text.getX(); - double xTM = text.getMaxX(); - double yT = text.getY(); - double yTM = text.getMaxY(); - size.moveTo(xV, yV); - size.lineTo(xVM, yV); - size.lineTo(xVM, yT); - size.lineTo(xTM, yT); - size.lineTo(xTM, yTM); - size.lineTo(xT, yTM); - size.lineTo(xT, yT); - size.lineTo(xV, yT); - size.closePath(); - return size; - } - - private Double getBoundsPathTop(Path2D.Double size, Rectangle2D valve, - Rectangle2D text) { - double xV = valve.getX(); - double xVM = valve.getMaxX(); - //double yV = valve.getY(); - double yVM = valve.getMaxY(); - double xT = text.getX(); - double xTM = text.getMaxX(); - double yT = text.getY(); - double yTM = text.getMaxY(); - size.moveTo(xT, yT); - size.lineTo(xTM, yT); - size.lineTo(xTM, yTM); - size.lineTo(xVM, yTM); - size.lineTo(xVM, yVM); - size.lineTo(xV, yVM); - size.lineTo(xV, yTM); - size.lineTo(xT, yTM); - size.closePath(); - return size; - } - - private Double getBoundsPathLeft(Path2D.Double size, Rectangle2D valve, - Rectangle2D text) { - double xV = valve.getX(); - double xVM = valve.getMaxX(); - double yV = valve.getY(); - double yVM = valve.getMaxY(); - double xT = text.getX(); - double xTM = text.getMaxX(); - double yT = text.getY(); - double yTM = text.getMaxY(); - size.moveTo(xT, yT); - size.lineTo(xTM, yT); - size.lineTo(xTM, yV); - size.lineTo(xVM, yV); - size.lineTo(xVM, yVM); - size.lineTo(xV, yVM); - size.lineTo(xV, yTM); - size.lineTo(xT, yTM); - size.closePath(); - return size; - } - - private Double getBoundsPathRight(Path2D.Double size, Rectangle2D valve, - Rectangle2D text) { - double xV = valve.getX(); - double xVM = valve.getMaxX(); - double yV = valve.getY(); - double yVM = valve.getMaxY(); - double xT = text.getX(); - double xTM = text.getMaxX(); - double yT = text.getY(); - double yTM = text.getMaxY(); - size.moveTo(xV, yV); - size.lineTo(xT, yV); - size.lineTo(xT, yT); - size.lineTo(xTM, yT); - size.lineTo(xTM, yTM); - size.lineTo(xVM, yTM); - size.lineTo(xVM, yVM); - size.lineTo(xV, yVM); - size.closePath(); - return size; - } - } - } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java index 37b6969b..afac8e42 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/ValveOutline.java @@ -1,9 +1,14 @@ package org.simantics.sysdyn.ui.elements; import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; +import org.simantics.diagram.elements.TextElementNoBounds; +import org.simantics.diagram.elements.TextNode; +import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.handler.InternalSize; import org.simantics.g2d.element.handler.impl.BoundsOutline; @@ -15,16 +20,38 @@ public class ValveOutline extends BoundsOutline { private static final long serialVersionUID = 5544256245734478634L; - public ValveOutline() { - super(); - } + public ValveOutline() { + super(); + } + + @Override + public Shape getElementShape(IElement e) { + TextNode textNode = e.getHint(TextElementNoBounds.SG_NODE); + ValveSceneGraph valveSG = e.getElementClass().getSingleItem(ValveSceneGraph.class); + + if(textNode != null && valveSG != null) { + try { + AffineTransform elementTransform = ElementUtils.getTransform(e); + AffineTransform nodeTransform = textNode.getTransform(); + + AffineTransform elementTransformInverse = elementTransform.createInverse(); + elementTransformInverse.concatenate(nodeTransform); + + Rectangle2D text = textNode.getBoundsInLocal(); + Shape textShape = elementTransformInverse.createTransformedShape(text); + + Rectangle2D valve = valveSG.getValveBounds(e, new Rectangle2D.Double()); + + Path2D path = new Path2D.Double(textShape); + path.append(valve, false); + + return path; + } catch (NoninvertibleTransformException e1) { + e1.printStackTrace(); + } + } - @Override - public Shape getElementShape(IElement e) { InternalSize b = e.getElementClass().getSingleItem(InternalSize.class); - if (b instanceof ValveSceneGraph) - return ((ValveSceneGraph)b).getBoundsPath(e, new Path2D.Double()); - else - return b.getBounds(e, new Rectangle2D.Double()); - } + return b.getBounds(e, new Rectangle2D.Double()); + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/RouteFlowConnectionFactory.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/RouteFlowConnectionFactory.java index 17489d80..567b48c4 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/RouteFlowConnectionFactory.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/connections/RouteFlowConnectionFactory.java @@ -242,19 +242,22 @@ public class RouteFlowConnectionFactory extends SyncElementFactory { // Get element bounds to decide allowed terminal direction(s) IElement te = graph.syncRequest(DiagramRequests.getElement(canvas, diagram, terminalElement, null)); - ElementUtils.getElementBounds(te, bounds); - - { - Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalElementTr); - bounds.setFrame(shp.getBounds2D()); - } - - // Valve behaves differently. The flow must start inside the valve bounds if(te.getElementClass().containsClass(ValveSceneGraph.class)) { + // Valve behaves differently. The flow must start inside the valve bounds + ValveSceneGraph vs = te.getElementClass().getSingleItem(ValveSceneGraph.class); + Rectangle2D size = new Rectangle2D.Double(); + vs.getValveBounds(te, size); + Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(size, terminalElementTr); + size = (Rectangle2D) shp; float lw = FlowConnectionStyle.LINE_WIDTH; - bounds.setFrame(new Rectangle2D.Double(bounds.getCenterX() - (lw/2), bounds.getCenterY() - (lw/2), lw, lw)); + bounds.setFrame(new Rectangle2D.Double(size.getCenterX() - (lw/2), size.getCenterY() - (lw/2), lw, lw)); + } else { + // Basic bounds + bounds = ElementUtils.getElementShape(te).getBounds2D(); + Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalElementTr); + bounds.setFrame(shp.getBounds2D()); } - + x = bounds.getCenterX(); y = bounds.getCenterY(); @@ -268,7 +271,6 @@ public class RouteFlowConnectionFactory extends SyncElementFactory { maxx = bounds.getMaxX(); maxy = bounds.getMaxY(); - Integer allowedDirections = graph.getPossibleRelatedValue(terminal, DIA.Terminal_AllowedDirections, Bindings.INTEGER); // Valve behaves differently. Allowed directions depend on the orientation of the valve -- 2.47.1