7e9296049ff19f7c066aac2aa89d852f0b59115f
[jalview.git] / src2 / fr / orsay / lri / varna / applications / templateEditor / GraphicalTemplateElement.java
1 package fr.orsay.lri.varna.applications.templateEditor;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Dimension;
6 import java.awt.Font;
7 import java.awt.FontMetrics;
8 import java.awt.Graphics2D;
9 import java.awt.Polygon;
10 import java.awt.Shape;
11 import java.awt.Stroke;
12 import java.awt.geom.Point2D;
13 import java.awt.geom.Rectangle2D;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16
17 import fr.orsay.lri.varna.exceptions.ExceptionEdgeEndpointAlreadyConnected;
18 import fr.orsay.lri.varna.exceptions.ExceptionInvalidRNATemplate;
19 import fr.orsay.lri.varna.models.templates.RNATemplate.EdgeEndPointPosition;
20 import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateElement;
21 import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateElement.EdgeEndPoint;
22
23 public abstract class GraphicalTemplateElement {
24                 
25         public boolean _debug = false;
26     protected HashMap<RelativePosition,Color> _mainColors = new HashMap<RelativePosition,Color>();
27     
28     public Color _dominantColor = new Color(0.5f,0.5f,0.5f,0.9f);
29         
30         public enum RelativePosition {
31                 RP_OUTER,RP_INNER_GENERAL,RP_INNER_MOVE,RP_EDIT_START,RP_EDIT_END,RP_CONNECT_START5,RP_CONNECT_START3,RP_CONNECT_END5,RP_CONNECT_END3,
32                 RP_EDIT_TANGENT_3,RP_EDIT_TANGENT_5;
33         };
34         
35         static final Color  BACKBONE_COLOR = Color.gray;
36         static final Color  CONTROL_COLOR = Color.decode("#D0D0FF");
37         static final Font  NUMBER_FONT = new Font("Arial", Font.BOLD,18);
38         static final Color NUMBER_COLOR = Color.gray;
39         static final Color  BASE_PAIR_COLOR = Color.blue;
40         static final Color  BASE_COLOR = Color.gray;
41         static final Color  BASE_FILL_COLOR = Color.white;
42         static final Color  BASE_FILL_3_COLOR = Color.red;
43         static final Color  BASE_FILL_5_COLOR = Color.green;
44         static final Color  MAGNET_COLOR = CONTROL_COLOR;
45
46         public void setDominantColor(Color c)
47         {
48                 _dominantColor = c;
49         }
50
51         public Color getDominantColor()
52         {
53                 return _dominantColor;
54         }
55
56         public abstract RelativePosition getRelativePosition(double x, double y);
57         
58         public abstract void draw(Graphics2D g2d, boolean selected);
59         public abstract Polygon getBoundingPolygon();
60         public abstract void translate(double x, double y);
61         public abstract RelativePosition getClosestEdge(double x, double y);
62         public abstract ArrayList<RelativePosition> getConnectedEdges();
63         public abstract RNATemplateElement getTemplateElement();
64         public void setMainColor(RelativePosition edge,Color c)
65         {
66                 _mainColors.put(edge, c);
67         }
68
69         public abstract Shape getArea();
70         
71         public void attach(GraphicalTemplateElement e, RelativePosition edgeOrig, RelativePosition edgeDest) throws ExceptionEdgeEndpointAlreadyConnected, ExceptionInvalidRNATemplate
72         {
73                 _attachedElements.put(edgeOrig, new Couple<RelativePosition,GraphicalTemplateElement>(edgeDest,e));
74         }
75         
76         
77         /**
78          * Same as attach(), but without touching the underlying
79          * RNATemplateElement objects.
80          * This is useful if the underlying RNATemplate already contains edges
81          * but not the graphical template.
82          */
83         public void graphicalAttach(GraphicalTemplateElement e, RelativePosition edgeOrig, RelativePosition edgeDest)
84         {
85                 _attachedElements.put(edgeOrig, new Couple<RelativePosition,GraphicalTemplateElement>(edgeDest,e));
86         }
87         
88         public void detach(RelativePosition edge)
89         {
90                 if (_attachedElements.containsKey(edge))
91                 {
92                         Couple<RelativePosition,GraphicalTemplateElement> c = _attachedElements.get(edge);
93                         _attachedElements.remove(edge);
94                         c.second.detach(c.first);
95                 }
96         }
97         public Couple<RelativePosition,GraphicalTemplateElement> getAttachedElement(RelativePosition localedge)
98         {
99                 if (_attachedElements.containsKey(localedge))
100                         return _attachedElements.get(localedge);
101                 return null;
102         }
103         public boolean hasAttachedElement(RelativePosition localedge)
104         {
105                 return _attachedElements.containsKey(localedge);
106         }
107         public abstract EdgeEndPoint getEndPoint(RelativePosition r);
108         public abstract boolean isIn(RelativePosition r);
109         
110         public void draw(Graphics2D g2d)
111         {
112                 draw(g2d,false);
113         }
114         
115         private HashMap<RelativePosition,Couple<RelativePosition,GraphicalTemplateElement>> _attachedElements = new HashMap<RelativePosition,Couple<RelativePosition,GraphicalTemplateElement>>();
116
117         
118         private Dimension getStringDimension(Graphics2D g, String s) {
119                 FontMetrics fm = g.getFontMetrics();
120                 Rectangle2D r = fm.getStringBounds(s, g);
121                 return (new Dimension((int) r.getWidth(), (int) fm.getAscent()
122                                 - fm.getDescent()));
123         }
124
125         
126
127         public void drawStringCentered(Graphics2D g2, String res, double x,
128                         double y) {
129                 Dimension d = getStringDimension(g2, res);
130                 x -= (double) d.width / 2.0;
131                 y += (double) d.height / 2.0;
132                 if (_debug)
133                         g2.drawRect((int) x, (int) y - d.height, d.width, d.height);
134                 g2.drawString(res, (int) Math.round(x), (int) Math.round(y));
135         }
136         
137         protected Stroke  _boldStroke = new BasicStroke(2.5f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND, 3.0f);
138         protected Stroke  _solidStroke = new BasicStroke(1.5f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND, 3.0f);
139         private float[] dash = { 5.0f, 5.0f };
140         protected Stroke  _dashedStroke = new BasicStroke(1.5f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND, 3.0f, dash, 0);
141         
142         public abstract RelativePosition getConnectedEdge(RelativePosition edge);
143         public abstract Point2D.Double getEdgePosition(RelativePosition edge);
144         public abstract void setEdgePosition(RelativePosition edge, Point2D.Double pos);
145         public abstract RelativePosition relativePositionFromEdgeEndPointPosition(EdgeEndPointPosition endPointPosition);
146         
147         public static boolean canConnect(GraphicalTemplateElement el1, RelativePosition e1,GraphicalTemplateElement el2, RelativePosition e2)
148         {
149                 return (!el1.hasAttachedElement(e1))&&(!el2.hasAttachedElement(e2))&&(el1.isIn(e1)!=el2.isIn(e2));
150         }
151
152         
153         protected void drawMove(Graphics2D g2d, Point2D.Double center)
154         {
155                 g2d.setStroke(_solidStroke);
156                 g2d.setColor(CONTROL_COLOR);
157                 g2d.fillOval((int)((center.x-Helix.MOVE_RADIUS)), (int)((center.y-Helix.MOVE_RADIUS)), (int)(2.0*Helix.MOVE_RADIUS), (int)(2.0*Helix.MOVE_RADIUS));
158                 g2d.setColor(BACKBONE_COLOR);
159                 g2d.drawOval((int)((center.x-Helix.MOVE_RADIUS)), (int)((center.y-Helix.MOVE_RADIUS)), (int)(2.0*Helix.MOVE_RADIUS), (int)(2.0*Helix.MOVE_RADIUS));
160                 double arrowLength = Helix.MOVE_RADIUS-2.0;
161                 double width = 3.0;
162                 drawArrow(g2d,center,new Point2D.Double(center.x+arrowLength,center.y),width);
163                 drawArrow(g2d,center,new Point2D.Double(center.x-arrowLength,center.y),width);
164                 drawArrow(g2d,center,new Point2D.Double(center.x,center.y+arrowLength),width);
165                 drawArrow(g2d,center,new Point2D.Double(center.x,center.y-arrowLength),width);
166         }
167         
168         protected void drawEditStart(Graphics2D g2d, Helix h, double dx,double dy,double nx,double ny)
169         {
170                 Point2D.Double center = h.getCenterEditStart();
171                 drawEdit(g2d, center, dx,dy,nx,ny);
172         }
173         protected void drawEditEnd(Graphics2D g2d, Helix h, double dx,double dy,double nx,double ny)
174         {
175                 Point2D.Double center = h.getCenterEditEnd();
176                 drawEdit(g2d, center, dx,dy,nx,ny);
177         }
178
179         protected void drawEdit(Graphics2D g2d, Point2D.Double center, double dx,double dy,double nx,double ny)
180         {
181                 g2d.setColor(CONTROL_COLOR);
182                 g2d.fillOval((int)((center.x-Helix.EDIT_RADIUS)), (int)((center.y-Helix.EDIT_RADIUS)), (int)(2.0*Helix.EDIT_RADIUS), (int)(2.0*Helix.EDIT_RADIUS));
183                 g2d.setColor(BACKBONE_COLOR);
184                 g2d.drawOval((int)((center.x-Helix.EDIT_RADIUS)), (int)((center.y-Helix.EDIT_RADIUS)), (int)(2.0*Helix.EDIT_RADIUS), (int)(2.0*Helix.EDIT_RADIUS));
185                 double arrowLength = Helix.EDIT_RADIUS-2.0;
186                 double width = 3.0;
187                 drawArrow(g2d,center,new Point2D.Double(center.x+nx*arrowLength,center.y+ny*arrowLength),width);
188                 drawArrow(g2d,center,new Point2D.Double(center.x-nx*arrowLength,center.y-ny*arrowLength),width);
189                 drawArrow(g2d,center,new Point2D.Double(center.x+dx*arrowLength,center.y+dy*arrowLength),width);
190                 drawArrow(g2d,center,new Point2D.Double(center.x-dx*arrowLength,center.y-dy*arrowLength),width);
191         }
192         
193         protected void drawArrow(Graphics2D g2d, Point2D.Double orig, Point2D.Double dest, double width)
194         {
195                 g2d.setStroke(_solidStroke);
196                 g2d.drawLine((int)orig.x,(int)orig.y,(int)dest.x,(int)dest.y);
197                 double dx = (orig.x-dest.x)/(orig.distance(dest));
198                 double dy = (orig.y-dest.y)/(orig.distance(dest));
199                 double nx = dy;
200                 double ny = -dx;
201                 g2d.drawLine((int)dest.x,(int)dest.y,(int)(dest.x-width*(-dx+nx)),(int)(dest.y-width*(-dy+ny)));
202                 g2d.drawLine((int)dest.x,(int)dest.y,(int)(dest.x-width*(-dx-nx)),(int)(dest.y-width*(-dy-ny)));
203         }
204
205         
206         
207         protected void drawAnchor(Graphics2D g2d, Point2D.Double p)
208         { drawAnchor(g2d,p,CONTROL_COLOR); }
209
210         protected void drawAnchor5(Graphics2D g2d, Point2D.Double p)
211         { drawAnchor(g2d,p,BASE_FILL_5_COLOR); }
212
213         protected void drawAnchor3(Graphics2D g2d, Point2D.Double p)
214         { drawAnchor(g2d,p,BASE_FILL_3_COLOR); }
215         
216         protected void drawAnchor(Graphics2D g2d, Point2D.Double p, Color c)
217         {
218                 g2d.setColor(c);                                
219                 g2d.fillOval((int)(p.x-Helix.EDGE_BASE_RADIUS),(int)(p.y-Helix.EDGE_BASE_RADIUS),(int)(2.0*Helix.EDGE_BASE_RADIUS),(int)(2.0*Helix.EDGE_BASE_RADIUS));
220                 g2d.setColor(BASE_COLOR);                               
221                 g2d.drawOval((int)(p.x-Helix.EDGE_BASE_RADIUS),(int)(p.y-Helix.EDGE_BASE_RADIUS),(int)(2.0*Helix.EDGE_BASE_RADIUS),(int)(2.0*Helix.EDGE_BASE_RADIUS));
222
223         }
224
225         protected void drawMagnet(Graphics2D g2d, Point2D.Double p)
226         {
227                 drawAnchor(g2d, p, MAGNET_COLOR);                               
228                 g2d.setColor(BASE_COLOR);                               
229                 g2d.drawOval((int)(p.x-Helix.EDGE_BASE_RADIUS),(int)(p.y-Helix.EDGE_BASE_RADIUS),(int)(2.0*Helix.EDGE_BASE_RADIUS),(int)(2.0*Helix.EDGE_BASE_RADIUS));
230                 g2d.drawOval((int)(p.x-2),(int)(p.y-2),(int)(2.0*2),(int)(2.0*2));
231
232         }
233         
234         
235         
236         protected void drawBase(Graphics2D g2d, Point2D.Double p)
237         {
238                 g2d.setColor(BASE_FILL_COLOR);
239                 g2d.fillOval((int)(p.x-Helix.BASE_RADIUS),(int)(p.y-Helix.BASE_RADIUS),(int)(2.0*Helix.BASE_RADIUS),(int)(2.0*Helix.BASE_RADIUS));
240                 g2d.setColor(BASE_COLOR);
241                 g2d.drawOval((int)(p.x-Helix.BASE_RADIUS),(int)(p.y-Helix.BASE_RADIUS),(int)(2.0*Helix.BASE_RADIUS),(int)(2.0*Helix.BASE_RADIUS));
242         }
243
244         public boolean equals(Object b)
245         {
246           if (b instanceof GraphicalTemplateElement)
247           {
248                 return b==this;  
249           }
250           else
251                   return false;
252         }
253         
254 }