]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementPainter.java
Render elements using custom color filters
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / participant / ElementPainter.java
index d35bfadb04ba2fd7e92eefaaa4b5f7feda40440d..d4d0609b2766a3c9b616bba03b8a9f050d06a56b 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * Copyright (c) 2007, 2018 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
@@ -8,6 +8,7 @@
  *
  * Contributors:
  *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - GitLab issue #66
  *******************************************************************************/
 package org.simantics.g2d.diagram.participant;
 
@@ -60,6 +61,7 @@ import org.simantics.g2d.element.handler.BendsHandler;
 import org.simantics.g2d.element.handler.Children;
 import org.simantics.g2d.element.handler.Children.ChildEvent;
 import org.simantics.g2d.element.handler.Children.ChildListener;
+import org.simantics.g2d.element.handler.ElementLayers;
 import org.simantics.g2d.element.handler.FillColor;
 import org.simantics.g2d.element.handler.Outline;
 import org.simantics.g2d.element.handler.OutlineColorSpec;
@@ -70,9 +72,9 @@ import org.simantics.g2d.element.handler.SelectionSpecification;
 import org.simantics.g2d.element.handler.StrokeSpec;
 import org.simantics.g2d.element.handler.TerminalTopology;
 import org.simantics.g2d.element.handler.Transform;
-import org.simantics.g2d.layers.ILayer;
+import org.simantics.g2d.layers.ILayers;
+import org.simantics.g2d.layers.ILayers.ILayersListener;
 import org.simantics.g2d.layers.ILayersEditor;
-import org.simantics.g2d.layers.ILayersEditor.ILayersEditorListener;
 import org.simantics.g2d.participant.TransformUtil;
 import org.simantics.g2d.scenegraph.SceneGraphConstants;
 import org.simantics.g2d.utils.ElementNodeBridge;
@@ -82,6 +84,7 @@ import org.simantics.scenegraph.Node;
 import org.simantics.scenegraph.g2d.G2DParentNode;
 import org.simantics.scenegraph.g2d.G2DSceneGraph;
 import org.simantics.scenegraph.g2d.IG2DNode;
+import org.simantics.scenegraph.g2d.color.ColorFilter;
 import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
 import org.simantics.scenegraph.g2d.nodes.DataNode;
 import org.simantics.scenegraph.g2d.nodes.LinkNode;
@@ -136,11 +139,12 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
      * ElementPainter.
      */
     public static interface ISelectionProvider {
-        public void init(final IElement e, final G2DParentNode parentNode, final String nodeId,
+        public void init(int selectionId, final IElement e, final G2DParentNode parentNode, final String nodeId,
                 final AffineTransform transform, final Rectangle2D bounds, final Color color);
     }
 
     private static final boolean DEBUG                  = false;
+    private static final boolean NODE_TO_ELEMENT_MAPPING = true;
 
     public static final int      ELEMENT_PAINT_PRIORITY = 10;
 
@@ -156,7 +160,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
     SingleElementNode diagramParent;
     RTreeNode elementParent;
 
-    boolean paintSelectionFrames;
+    ElementPainterConfiguration cfg;
 
     /**
      * Internally reused to avert constant reallocation.
@@ -172,7 +176,11 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
     }
 
     public ElementPainter(boolean paintSelectionFrames) {
-        this.paintSelectionFrames = paintSelectionFrames;
+        this(new ElementPainterConfiguration().paintSelectionFrames(paintSelectionFrames));
+    }
+
+    public ElementPainter(ElementPainterConfiguration cfg) {
+        this.cfg = cfg;
     }
 
     @Override
@@ -198,17 +206,18 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
             return;
 
         if (oldValue != null) {
+            Map<INode, IElement> nodeToElementMap = oldValue.removeHint(DiagramHints.NODE_TO_ELEMENT_MAP);
             for (IElement e : oldValue.getElements()) {
-                removeElement(e);
+                removeElement(oldValue, e, nodeToElementMap);
             }
 
             oldValue.removeCompositionListener(this);
             oldValue.removeKeyHintListener(Hints.KEY_DIRTY, diagramHintListener);
             oldValue.removeKeyHintListener(Hints.KEY_DISABLE_PAINTING, diagramHintListener);
 
-            ILayersEditor layers = oldValue.getHint(DiagramHints.KEY_LAYERS_EDITOR);
+            ILayers layers = oldValue.getHint(DiagramHints.KEY_LAYERS);
             if (layers != null) {
-                layers.removeListener(layersListener);
+                layers.removeLayersListener(layersListener);
             }
 
             for (TransactionContext tc : oldValue.getDiagramClass().getItemsByClass(TransactionContext.class)) {
@@ -217,17 +226,22 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         }
 
         if (newValue != null) {
+            diagram.removeHint(DiagramHints.NODE_TO_ELEMENT_MAP);
+            Map<INode, IElement> nodeElementMap = NODE_TO_ELEMENT_MAPPING ? new HashMap<>() : null;
+            if (nodeElementMap != null)
+                diagram.setHint(DiagramHints.NODE_TO_ELEMENT_MAP, nodeElementMap);
+
             for (IElement e : newValue.getElements()) {
-                addElement(e, false);
+                addElement(newValue, e, false, nodeElementMap);
             }
 
             newValue.addCompositionListener(this);
             newValue.addKeyHintListener(Hints.KEY_DISABLE_PAINTING, diagramHintListener);
             newValue.addKeyHintListener(Hints.KEY_DIRTY, diagramHintListener);
 
-            ILayersEditor layers = newValue.getHint(DiagramHints.KEY_LAYERS_EDITOR);
+            ILayers layers = newValue.getHint(DiagramHints.KEY_LAYERS);
             if (layers != null) {
-                layers.addListener(layersListener);
+                layers.addLayersListener(layersListener);
             }
 
             for (TransactionContext tc : newValue.getDiagramClass().getItemsByClass(TransactionContext.class)) {
@@ -242,7 +256,8 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
     public void initSG(G2DParentNode parent) {
         diagramParent = parent.addNode("elements_"+Node.IDCOUNTER, UnboundedNode.class);
         diagramParent.setZIndex(ELEMENT_PAINT_PRIORITY);
-        elementParent = diagramParent.addNode("spatialRoot", RTreeNode.class);
+        elementParent = diagramParent.addNode(SceneGraphConstants.SPATIAL_ROOT_NODE_NAME, RTreeNode.class);
+        elementParent.setLookupId(SceneGraphConstants.SPATIAL_ROOT_NODE_ID);
         elementParent.setZIndex(0);
     }
 
@@ -289,41 +304,21 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
     // Layer configuration change listening and reaction logic
     // ------------------------------------------------------------------------
 
-    ILayersEditorListener layersListener = new ILayersEditorListener() {
-        private void layersChanged() {
+    ILayersListener layersListener = new ILayersListener() {
+        @Override
+        public void changed() {
             Object task = BEGIN("EP.layersChanged");
-            // Update visibility/focusability for each node only, do not reinitialize the graphics.
+            ICanvasContext ctx = getContext();
+            if(ctx != null) {
+                G2DSceneGraph sg = ctx.getSceneGraph();
+                if(sg != null) {
+                    ILayersEditor layers = diagram.getHint(DiagramHints.KEY_LAYERS);
+                    sg.setGlobalProperty(G2DSceneGraph.IGNORE_FOCUS, layers.getIgnoreFocusSettings());
+                }
+            }
             updateAllVisibility();
             END(task);
         }
-        @Override
-        public void layerRemoved(ILayer layer) {
-            layersChanged();
-        }
-        @Override
-        public void layerDeactivated(ILayer layer) {
-            layersChanged();
-        }
-        @Override
-        public void layerAdded(ILayer layer) {
-            layersChanged();
-        }
-        @Override
-        public void layerActivated(ILayer layer) {
-            layersChanged();
-        }
-        @Override
-        public void ignoreFocusChanged(boolean value) {
-               ICanvasContext ctx = getContext();
-               if(ctx == null) return;
-               G2DSceneGraph sg = ctx.getSceneGraph();
-               if(sg == null) return;
-               sg.setGlobalProperty(G2DSceneGraph.IGNORE_FOCUS, value);
-        }
-        @Override
-        public void ignoreVisibilityChanged(boolean value) {
-            layersChanged();
-        }
     };
 
     protected void updateAllVisibility() {
@@ -392,11 +387,17 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                 }
             } else if (key == ElementHints.KEY_FOCUS_LAYERS || key == ElementHints.KEY_VISIBLE_LAYERS) {
                 if (sender instanceof IElement) {
-                    assert getContext().getThreadAccess().currentThreadAccess();
-                    IElement e = (IElement) sender;
-                    Object task = BEGIN("layers changed: " + e);
-                    update(e);
-                    END(task);
+                    getContext().getThreadAccess().asyncExec(new Runnable() {
+
+                        @Override
+                        public void run() {
+                            assert getContext().getThreadAccess().currentThreadAccess();
+                            IElement e = (IElement) sender;
+                            Object task = BEGIN("layers changed: " + e);
+                            update(e);
+                            END(task);
+                        }
+                    });
                 }
             }
         }
@@ -499,10 +500,11 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         if (DEBUG)
             System.out.println("EP.onElementAdded(" + d + ", " + e + ")");
 
+        Map<INode, IElement> nodeElementMap = diagram.getHint(DiagramHints.NODE_TO_ELEMENT_MAP);
         if (inDiagramTransaction()) {
-            addElement(e, false);
+            addElement(d, e, false, nodeElementMap);
         } else {
-            addElement(e, true);
+            addElement(d, e, true, nodeElementMap);
         }
     }
     @Override
@@ -510,7 +512,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         if (DEBUG)
             System.out.println("EP.onElementRemoved(" + d + ", " + e + ")");
 
-        removeElement(e);
+        removeElement(d, e, diagram.getHint(DiagramHints.NODE_TO_ELEMENT_MAP));
     }
 
     @Override
@@ -518,17 +520,19 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         if (DEBUG)
             System.out.println("EP.elementChildrenChanged: " + event);
 
+        Map<INode, IElement> nodeElementMap = diagram.getHint(DiagramHints.NODE_TO_ELEMENT_MAP);
+
         for (IElement removed : event.removed) {
-            removeElement(removed);
+            removeElement(diagram, removed, nodeElementMap);
         }
         for (IElement added : event.added) {
-            addElement(added, false);
+            addElement(diagram, added, false, nodeElementMap);
         }
     }
 
     private final List<IElement> childrenTemp = new ArrayList<IElement>();
 
-    public void addElement(IElement e, boolean synchronizeSceneGraphNow) {
+    public void addElement(IDiagram d, IElement e, boolean synchronizeSceneGraphNow, Map<INode, IElement> nodeElementMap) {
         if (DEBUG)
             System.out.println("EP.addElement(now=" + synchronizeSceneGraphNow + ", " + e + ")");
 
@@ -563,6 +567,8 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                 holder.setTransferableProvider(new ElementTransferableProvider(getContext(), e));
                 e.setHint(sgKey, holder);
                 holder.setZIndex(parentNode.getNodeCount() + 1);
+                if (nodeElementMap != null)
+                    nodeElementMap.put(holder, e);
             }
 
         } else {
@@ -575,6 +581,8 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                 holder.setTransferableProvider(new ElementTransferableProvider(getContext(), e));
                 e.setHint(sgKey, holder);
                 holder.setZIndex(parentNode.getNodeCount() + 1);
+                if (nodeElementMap != null)
+                    nodeElementMap.put(holder, e);
             }
 
         }
@@ -587,7 +595,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
             children.getChildren(e, childrenTemp);
             //System.out.println("children: " + childrenTemp);
             for (IElement child : childrenTemp) {
-                addElement(child, false);
+                addElement(d, child, false, nodeElementMap);
             }
             childrenTemp.clear();
         }
@@ -598,7 +606,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         //setTreeDirty();
     }
 
-    protected void removeElement(IElement e) {
+    protected void removeElement(IDiagram d, IElement e, Map<INode, IElement> nodeElementMap) {
         if (DEBUG)
             System.out.println("EP.removeElement(" + e + ")");
 
@@ -624,6 +632,8 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
             Node n = e.removeHint(sgKey);
             if (n != null) {
                 n.remove();
+                if (nodeElementMap != null)
+                    nodeElementMap.remove(n);
             }
         }
 
@@ -753,14 +763,6 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
             if (ElementUtils.isHidden(e))
                 return null;
 
-//            ElementClass ec = e.getElementClass();
-//            ILayers layers = diagram.getHint(DiagramHints.KEY_LAYERS);
-//            if (layers != null && !layers.getIgnoreVisibilitySettings()) {
-//                ElementLayers el = ec.getAtMostOneItemOfClass(ElementLayers.class);
-//                if (el != null && !el.isVisible(e, layers)) {
-//                    return null;
-//                }
-//            }
 
             // Update the node scene graph through SceneGraph handlers.
             List<SceneGraph> nodeHandlers = e.getElementClass().getItemsByClass(SceneGraph.class);
@@ -775,7 +777,19 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                 e.setHint(elementSgNodeKey, holder);
             }
             holder.setComposite(composite);
-            holder.setVisible(true);
+            boolean visible = true;
+            ElementClass ec = e.getElementClass();
+            ILayers layers = diagram.getHint(DiagramHints.KEY_LAYERS);
+            if (layers != null && !layers.getIgnoreVisibilitySettings()) {
+                ElementLayers el = ec.getAtMostOneItemOfClass(ElementLayers.class);
+                if (el != null && !el.isVisible(e, layers)) {
+                    visible = false;
+                }
+            }
+            holder.setVisible(visible);
+
+            ColorFilter colorFilter = e.getHint(ElementHints.KEY_COLOR_FILTER);
+            holder.setColorFilter(colorFilter);
 
             for (SceneGraph n : nodeHandlers) {
                 n.init(e, holder);
@@ -810,7 +824,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         Object task = BEGIN("EP.updateSelections");
 
         try {
-            if (!paintSelectionFrames)
+            if (!cfg.paintSelectionFrames)
                 return;
             if (selection == null)
                 return;
@@ -916,7 +930,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         Object task = BEGIN("EP.updateSelection");
 
         try {
-            if (!paintSelectionFrames)
+            if (!cfg.paintSelectionFrames)
                 return;
 
             G2DParentNode elementNode = (G2DParentNode) el.getHint(ElementHints.KEY_SG_NODE);
@@ -935,7 +949,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                     continue;
 
                 if (NodeUtil.needSelectionPaint(elementNode))
-                    paintSelectionFrame(elementNode, selectionNode, el, color);
+                    paintSelectionFrame(selectionId, elementNode, selectionNode, el, color);
 
                 nodesUpdated = true;
             }
@@ -962,12 +976,14 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         Color color = getSelectionColor(selectionId);
         G2DParentNode selectionsNode = getSelectionsNode(selectionId);
 
+        Class<? extends G2DParentNode> selectionNodeClass = cfg.selectionNodeClass != null ? cfg.selectionNodeClass : G2DParentNode.class;
+
         for (IElement e : selection) {
             Node elementNode = e.getHint(ElementHints.KEY_SG_NODE);
 //            System.out.println("selectionNode: " + elementNode + " " + e);
             if (elementNode instanceof G2DParentNode) {
                 G2DParentNode en = (G2DParentNode) elementNode;
-                G2DParentNode selectionNode = en.getOrCreateNode(NodeUtil.SELECTION_NODE_NAME, G2DParentNode.class);
+                G2DParentNode selectionNode = en.getOrCreateNode(NodeUtil.SELECTION_NODE_NAME, selectionNodeClass);
                 selectionNode.setZIndex(SELECTION_PAINT_PRIORITY);
                 if (selectionNodes != null)
                     selectionNodes.add(selectionNode);
@@ -981,7 +997,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                 createSelectionReference(selectionsNode, elementNode);
 
                 if (NodeUtil.needSelectionPaint(elementNode))
-                    paintSelectionFrame(en, selectionNode, e, color);
+                    paintSelectionFrame(selectionId, en, selectionNode, e, color);
 
             } else {
                 if (elementNode != null) {
@@ -1009,7 +1025,18 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         return result;
     }
 
-    public void paintSelectionFrame(G2DParentNode elementNode, G2DParentNode selectionNode, final IElement e, Color color) {
+    
+    /**
+     * We need to have separate class for SelectionNode, so that SCLSceneGraph can handle this properly.
+     * 
+     */
+    public static class SelectionShapeNode extends ShapeNode {
+
+               private static final long serialVersionUID = -5393630944240940166L;
+       
+    }
+    
+    public void paintSelectionFrame(int selectionId, G2DParentNode elementNode, G2DParentNode selectionNode, final IElement e, Color color) {
         // The element node already has the correct transform.
         AffineTransform selectionTransform = ElementUtils.getTransform(e);// no it doesnt ... new AffineTransform();
         Shape shape = ElementUtils.getElementShapeOrBounds(e);
@@ -1030,7 +1057,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
                 Outline outline = (Outline) es.getAdapter(Outline.class);
                 if (outline == null || outline.getElementShape(e) == null)
                        continue;
-                ShapeNode shapenode = shapeholder.getOrCreateNode(getNodeId("outline", e, es), ShapeNode.class);
+                ShapeNode shapenode = shapeholder.getOrCreateNode(getNodeId("outline", e, es), SelectionShapeNode.class);
 //                shapenode.setShape(es.getSelectionShape(e));
 //                shapenode.setStroke(SELECTION_STROKE);
 //                shapenode.setScaleStroke(true);
@@ -1066,7 +1093,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
             G2DParentNode shapeholder = selectionNode.getOrCreateNode(getNodeId("outlines", e), G2DParentNode.class);
 
             for (SelectionOutline es : shapeHandlers) {
-                ShapeNode shapenode = shapeholder.getOrCreateNode(getNodeId("outline", e, es), ShapeNode.class);
+                ShapeNode shapenode = shapeholder.getOrCreateNode(getNodeId("outline", e, es), SelectionShapeNode.class);
 //                shapenode.setShape(es.getSelectionShape(e));
 //                shapenode.setStroke(SELECTION_STROKE);
 //                shapenode.setScaleStroke(true);
@@ -1086,10 +1113,13 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
 
         ISelectionProvider provider = this.getContext().getDefaultHintContext().getHint(KEY_SELECTION_PROVIDER);
         if (provider != null) {
-            provider.init(e, selectionNode, getNodeId("shape", e), selectionTransform, bounds, color);
+            provider.init(selectionId, e, selectionNode, getNodeId("shape", e), selectionTransform, bounds, color);
         } else {
             SelectionNode s = selectionNode.getOrCreateNode(getNodeId("shape", e), SelectionNode.class);
-            s.init(selectionTransform, bounds, color);
+            s.init(selectionId, selectionTransform, bounds, color);
+            Double paddingFactor = diagram.getHint(DiagramHints.SELECTION_PADDING_SCALE_FACTOR);
+            if (paddingFactor != null)
+                s.setPaddingFactor(paddingFactor);
         }
     }