]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
5e5f981cf29c274a6d70e3be7de432b6f5c014bc
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2013 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     Semantum Oy - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.sysdyn.ui.elements.profiles;\r
13 \r
14 import java.awt.BasicStroke;\r
15 import java.awt.Color;\r
16 import java.awt.Stroke;\r
17 import java.awt.geom.AffineTransform;\r
18 import java.awt.geom.Rectangle2D;\r
19 import java.util.Collection;\r
20 \r
21 import org.simantics.db.ReadGraph;\r
22 import org.simantics.db.Resource;\r
23 import org.simantics.db.exception.DatabaseException;\r
24 import org.simantics.db.layer0.variable.Variable;\r
25 import org.simantics.diagram.elements.TextNode;\r
26 import org.simantics.diagram.profile.StyleBase;\r
27 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
28 import org.simantics.modeling.ModelingResources;\r
29 import org.simantics.scenegraph.INode;\r
30 import org.simantics.scenegraph.g2d.nodes.ShapeNode;\r
31 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;\r
32 import org.simantics.scenegraph.profile.EvaluationContext;\r
33 import org.simantics.scenegraph.profile.common.ProfileVariables;\r
34 import org.simantics.scenegraph.utils.GeometryUtils;\r
35 import org.simantics.scenegraph.utils.NodeUtil;\r
36 import org.simantics.sysdyn.SysdynResource;\r
37 import org.simantics.sysdyn.ui.elements.profiles.ShadowResult.Style;\r
38 import org.simantics.utils.datastructures.map.Tuple;\r
39 \r
40 public class ShadowStyle extends StyleBase<ShadowResult> {\r
41     \r
42     private static String SHADOW_DECORATION_NODE = "SHADOW_DECORATION_NODE";  \r
43     private static Stroke SHADOW_DECORATION_STROKE = new BasicStroke(0.2f);\r
44     \r
45     @Override\r
46     public ShadowResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {\r
47         ModelingResources MOD = ModelingResources.getInstance(graph);\r
48         SysdynResource SR = SysdynResource.getInstance(graph);\r
49         \r
50         AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element);\r
51         \r
52         Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);\r
53 \r
54         Resource original = graph.getPossibleObject(component, SR.Shadow_original);\r
55         Collection<Resource> shadows = graph.getObjects(component, SR.Shadow_original_Inverse);\r
56         \r
57         for(Resource r : graph.getObjects(runtimeDiagram, SR.ConfigurationDiagram_selection)) {\r
58             Resource selection = graph.getPossibleObject(r, MOD.ElementToComponent);\r
59             if(original != null) {\r
60                 Collection<Resource> otherShadows = graph.getObjects(original, SR.Shadow_original_Inverse);\r
61                 otherShadows.remove(component);\r
62                 if(selection.equals(original) || otherShadows.contains(selection)) {\r
63                     return new ShadowResult(Style.SHADOW, transform);\r
64                 }\r
65             }\r
66 \r
67             if(shadows.contains(selection)) {\r
68                 return new ShadowResult(Style.ORIGINAL, transform);\r
69             }\r
70         }\r
71         \r
72         return new ShadowResult(Style.NONE, transform);\r
73     }\r
74     \r
75     public void applyStyleForNode(EvaluationContext observer, INode _node, ShadowResult result) {\r
76         \r
77         if(result == null || result.getStyle() == Style.NONE) {\r
78             cleanupStyleForNode(_node);\r
79             return;\r
80         }\r
81         // Create a node that will show the style effect\r
82         A node = ProfileVariables.claimChild(_node, "", SHADOW_DECORATION_NODE, A.class, observer);\r
83         if (node == null)\r
84             return;\r
85         \r
86         AffineTransform at = result.getTransform();\r
87 \r
88         // Create a node for the style\r
89         INode n = NodeUtil.getNearestChildByClass((SingleElementNode)_node, TextNode.class);\r
90         Rectangle2D expandedElementBounds = GeometryUtils.expandRectangle( NodeUtil.getLocalElementBounds(n), 0.0);\r
91         node.setFill(false);\r
92         node.setColor(result.getStyle() == Style.SHADOW ? Color.BLUE : Color.MAGENTA);\r
93         node.setStroke(SHADOW_DECORATION_STROKE);\r
94         node.setValue("shape", expandedElementBounds);\r
95         node.setTransform(at);\r
96 \r
97         // Find z-index for the TextNode associated with the element and place the style node just below that text node \r
98         int zIndex = -1;\r
99         if(n != null) {\r
100             at = ((TextNode)n).getTransform();\r
101             zIndex = ((TextNode)n).getZIndex() - 1;\r
102         } else {\r
103             n = _node;\r
104         }\r
105         node.setZIndex(zIndex);\r
106 \r
107     }\r
108 \r
109     @Override\r
110     protected void cleanupStyleForNode(INode node) {\r
111         ProfileVariables.denyChild(node, "", SHADOW_DECORATION_NODE);\r
112     }\r
113     \r
114     /**\r
115      * Dummy class for displaying the style\r
116      * \r
117      * @author Teemu Lempinen\r
118      *\r
119      */\r
120     public static class A extends ShapeNode {\r
121 \r
122         private static final long serialVersionUID = -5273246617906214956L;\r
123 \r
124         @Override\r
125         public Rectangle2D getBoundsInLocal() {\r
126             return null;\r
127         }\r
128 \r
129         @Override\r
130         public Rectangle2D getBoundsInLocal(boolean b) {\r
131             return null;\r
132         }\r
133 \r
134         @Override\r
135         public Rectangle2D getBounds() {\r
136             return null;\r
137         }\r
138 \r
139     }\r
140     \r
141 }\r
142 \r
143 /**\r
144  * This is needed to keep the issue decoration up-to-date when its parent\r
145  * element moves.\r
146  */\r
147 class ShadowResult extends Tuple {\r
148     \r
149     public enum Style{NONE, ORIGINAL, SHADOW};\r
150     \r
151     public ShadowResult(Style style, AffineTransform transform) {\r
152         super(style, transform);\r
153     }\r
154     public Style getStyle() {\r
155         return (Style) getField(0);\r
156     }\r
157     \r
158     public AffineTransform getTransform() {\r
159         return (AffineTransform) getField(1);\r
160     }\r
161 }\r