1 /*******************************************************************************
\r
2 * Copyright (c) 2013 Association for Decentralized Information Management in
\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
10 * Semantum Oy - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.sysdyn.ui.elements.profiles;
\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
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
40 public class ShadowStyle extends StyleBase<ShadowResult> {
\r
42 private static String SHADOW_DECORATION_NODE = "SHADOW_DECORATION_NODE";
\r
43 private static Stroke SHADOW_DECORATION_STROKE = new BasicStroke(0.2f);
\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
50 AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element);
\r
52 Resource component = graph.getPossibleObject(element, MOD.ElementToComponent);
\r
54 Resource original = graph.getPossibleObject(component, SR.Shadow_original);
\r
55 Collection<Resource> shadows = graph.getObjects(component, SR.Shadow_original_Inverse);
\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
67 if(shadows.contains(selection)) {
\r
68 return new ShadowResult(Style.ORIGINAL, transform);
\r
72 return new ShadowResult(Style.NONE, transform);
\r
75 public void applyStyleForNode(EvaluationContext observer, INode _node, ShadowResult result) {
\r
77 if(result == null || result.getStyle() == Style.NONE) {
\r
78 cleanupStyleForNode(_node);
\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
86 AffineTransform at = result.getTransform();
\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
97 // Find z-index for the TextNode associated with the element and place the style node just below that text node
\r
100 at = ((TextNode)n).getTransform();
\r
101 zIndex = ((TextNode)n).getZIndex() - 1;
\r
105 node.setZIndex(zIndex);
\r
110 protected void cleanupStyleForNode(INode node) {
\r
111 ProfileVariables.denyChild(node, "", SHADOW_DECORATION_NODE);
\r
115 * Dummy class for displaying the style
\r
117 * @author Teemu Lempinen
\r
120 public static class A extends ShapeNode {
\r
122 private static final long serialVersionUID = -5273246617906214956L;
\r
125 public Rectangle2D getBoundsInLocal() {
\r
130 public Rectangle2D getBoundsInLocal(boolean b) {
\r
135 public Rectangle2D getBounds() {
\r
144 * This is needed to keep the issue decoration up-to-date when its parent
\r
147 class ShadowResult extends Tuple {
\r
149 public enum Style{NONE, ORIGINAL, SHADOW};
\r
151 public ShadowResult(Style style, AffineTransform transform) {
\r
152 super(style, transform);
\r
154 public Style getStyle() {
\r
155 return (Style) getField(0);
\r
158 public AffineTransform getTransform() {
\r
159 return (AffineTransform) getField(1);
\r