Load and Save trees.
[jalview.git] / src / jalview / gui / RotatableCanvas.java
1 package jalview.gui;\r
2 \r
3 import jalview.math.*;\r
4 import jalview.datamodel.*;\r
5 import jalview.util.*;\r
6 \r
7 import java.awt.*;\r
8 import java.awt.event.*;\r
9 import javax.swing.*;\r
10 import java.util.*;\r
11 \r
12 \r
13 public class RotatableCanvas extends JPanel implements MouseListener,\r
14                                                        MouseMotionListener,\r
15                                                        KeyListener\r
16                                                        //RubberbandListener,\r
17                                                        //SequenceSelectionListener\r
18 {\r
19   RotatableMatrix idmat  = new RotatableMatrix(3,3);\r
20   RotatableMatrix objmat = new RotatableMatrix(3,3);\r
21   RotatableMatrix rotmat = new RotatableMatrix(3,3);\r
22 \r
23   //RubberbandRectangle rubberband;\r
24 \r
25   boolean drawAxes = true;\r
26 \r
27   int omx = 0;\r
28   int mx = 0;\r
29   int omy = 0;\r
30   int my = 0;\r
31 \r
32   Image img;\r
33   Graphics ig;\r
34 \r
35   Dimension prefsize;\r
36 \r
37   float centre[] = new float[3];\r
38   float width[] = new float[3];\r
39 \r
40   float max[] = new float[3];\r
41   float min[] = new float[3];\r
42 \r
43   float maxwidth;\r
44   float scale;\r
45 \r
46   int npoint;\r
47 \r
48   Vector points;\r
49   float[][] orig;\r
50   float[][] axes;\r
51 \r
52   int startx;\r
53   int starty;\r
54 \r
55   int lastx;\r
56   int lasty;\r
57 \r
58   int rectx1;\r
59   int recty1;\r
60   int rectx2;\r
61   int recty2;\r
62 \r
63   float scalefactor = 1;\r
64 \r
65   AlignViewport av;\r
66 //  Controller    controller;\r
67 \r
68 \r
69   public RotatableCanvas(AlignViewport av,\r
70                           Vector points, int npoint) {\r
71     this.points = points;\r
72     this.npoint = npoint;\r
73     this.av = av;\r
74     ToolTipManager.sharedInstance().registerComponent(this);\r
75     PaintRefresher.Register(this);\r
76 //\r
77     prefsize = getPreferredSize();\r
78     orig = new float[npoint][3];\r
79 \r
80     for (int i=0; i < npoint; i++) {\r
81       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
82       for (int j=0; j < 3; j++) {\r
83         orig[i][j] = sp.coord[j];\r
84       }\r
85     }\r
86     //Initialize the matrices to identity\r
87 \r
88     for (int i = 0; i < 3; i++) {\r
89       for (int j = 0; j < 3 ; j++) {\r
90         if (i != j) {\r
91           idmat.addElement(i,j,0);\r
92           objmat.addElement(i,j,0);\r
93           rotmat.addElement(i,j,0);\r
94         } else {\r
95           idmat.addElement(i,j,0);\r
96           objmat.addElement(i,j,0);\r
97           rotmat.addElement(i,j,0);\r
98         }\r
99       }\r
100     }\r
101 \r
102     axes = new float[3][3];\r
103     initAxes();\r
104 \r
105     findCentre();\r
106     findWidth();\r
107 \r
108     scale = findScale();\r
109 \r
110     //    System.out.println("Scale factor = " + scale);\r
111 \r
112     addMouseListener(this);\r
113     addKeyListener(this);\r
114    // if (getParent() != null) {\r
115    //   getParent().addKeyListener(this);\r
116     //}\r
117     addMouseMotionListener(this);\r
118 \r
119     // Add rubberband\r
120  //   rubberband  = new RubberbandRectangle(this);\r
121   //  rubberband.setActive(true);\r
122  //   rubberband.addListener(this);\r
123   }\r
124 \r
125  /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {\r
126     redrawneeded = true;\r
127     repaint();\r
128     return true;\r
129   }\r
130 \r
131   public void removeNotify() {\r
132     controller.removeListener(this);\r
133     super.removeNotify();\r
134   }*/\r
135 \r
136   public void initAxes() {\r
137     for (int i = 0; i < 3; i++) {\r
138       for (int j=0; j < 3; j++) {\r
139         if (i != j) {\r
140           axes[i][j] = 0;\r
141         } else {\r
142           axes[i][j] = 1;\r
143         }\r
144       }\r
145     }\r
146   }\r
147 \r
148   public void findWidth() {\r
149     max = new float[3];\r
150     min = new float[3];\r
151 \r
152     max[0] = (float)-1e30;\r
153     max[1] = (float)-1e30;\r
154     max[2] = (float)-1e30;\r
155 \r
156     min[0] = (float)1e30;\r
157     min[1] = (float)1e30;\r
158     min[2] = (float)1e30;\r
159 \r
160     for (int i = 0; i < 3; i++) {\r
161       for (int j = 0; j < npoint; j++) {\r
162         SequencePoint sp = (SequencePoint)points.elementAt(j);\r
163         if (sp.coord[i] >= max[i]) {\r
164           max[i] = sp.coord[i];\r
165         }\r
166         if (sp.coord[i] <= min[i]) {\r
167           min[i] = sp.coord[i];\r
168         }\r
169       }\r
170     }\r
171 \r
172     //    System.out.println("xmax " + max[0] + " min " + min[0]);\r
173     //System.out.println("ymax " + max[1] + " min " + min[1]);\r
174     //System.out.println("zmax " + max[2] + " min " + min[2]);\r
175 \r
176     width[0] = Math.abs(max[0] - min[0]);\r
177     width[1] = Math.abs(max[1] - min[1]);\r
178     width[2] = Math.abs(max[2] - min[2]);\r
179 \r
180     maxwidth = width[0];\r
181 \r
182     if (width[1] > width[0])\r
183       maxwidth = width[1];\r
184     if (width[2] > width[1])\r
185       maxwidth = width[2];\r
186 \r
187     //System.out.println("Maxwidth = " + maxwidth);\r
188   }\r
189 \r
190   public float findScale() {\r
191     int dim, width, height;\r
192     if (getWidth() != 0) {\r
193       width = getWidth();\r
194       height = getHeight();\r
195     } else {\r
196       width = prefsize.width;\r
197       height = prefsize.height;\r
198     }\r
199 \r
200     if (width < height) {\r
201       dim = width;\r
202     } else {\r
203       dim = height;\r
204     }\r
205 \r
206     return (float)(dim*scalefactor/(2*maxwidth));\r
207   }\r
208 \r
209   public void findCentre() {\r
210     //Find centre coordinate\r
211     findWidth();\r
212 \r
213     centre[0] = (max[0] + min[0])/2;\r
214     centre[1] = (max[1] + min[1])/2;\r
215     centre[2] = (max[2] + min[2])/2;\r
216 \r
217     //    System.out.println("Centre x " + centre[0]);\r
218     //System.out.println("Centre y " + centre[1]);\r
219     //System.out.println("Centre z " + centre[2]);\r
220   }\r
221 \r
222   public Dimension getPreferredSize() {\r
223     if (prefsize != null) {\r
224       return prefsize;\r
225     } else {\r
226       return new Dimension(400,400);\r
227     }\r
228   }\r
229 \r
230   public Dimension getMinimumSize() {\r
231     return getPreferredSize();\r
232   }\r
233 \r
234   public void paintComponent(Graphics g) {\r
235     //Only create the image at the beginning -\r
236     if ((img == null) || (prefsize.width != getWidth()) || (prefsize.height != getHeight())) {\r
237       prefsize.width = getWidth();\r
238       prefsize.height = getHeight();\r
239 \r
240       scale = findScale();\r
241 \r
242       //      System.out.println("New scale = " + scale);\r
243       img = createImage(getWidth(),getHeight());\r
244       ig = img.getGraphics();\r
245 \r
246     }\r
247 \r
248 \r
249       drawBackground(ig,Color.black);\r
250       drawScene(ig);\r
251       if (drawAxes == true)\r
252       {\r
253         drawAxes(ig);\r
254       }\r
255 \r
256 \r
257     g.drawImage(img,0,0,this);\r
258   }\r
259 \r
260   public void drawAxes(Graphics g) {\r
261 \r
262     g.setColor(Color.yellow);\r
263     for (int i=0; i < 3 ; i++) {\r
264       g.drawLine(getWidth()/2,getHeight()/2,\r
265                  (int)(axes[i][0]*scale*max[0] + getWidth()/2),\r
266                  (int)(axes[i][1]*scale*max[1] + getHeight()/2));\r
267     }\r
268   }\r
269 \r
270   public void drawBackground(Graphics g, Color col) {\r
271     g.setColor(col);\r
272     g.fillRect(0,0,prefsize.width,prefsize.height);\r
273   }\r
274 \r
275 \r
276   public void drawScene(Graphics g) {\r
277     boolean darker = false;\r
278 \r
279     int halfwidth = getWidth()/2;\r
280     int halfheight = getHeight()/2;\r
281 \r
282     for (int i = 0; i < npoint; i++) {\r
283       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
284       int x = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;\r
285       int y = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;\r
286       float z = sp.coord[1] - centre[2];\r
287 \r
288 \r
289 \r
290 \r
291       if (sp.sequence.getColor() == Color.black)\r
292           g.setColor(Color.white);\r
293       else\r
294           g.setColor(sp.sequence.getColor());\r
295 \r
296 \r
297       if (av.getSelectionGroup() != null)\r
298       {\r
299         if (av.getSelectionGroup().sequences.contains(((SequencePoint)points.elementAt(i)).sequence))\r
300           g.setColor(Color.gray);\r
301       }\r
302       if (z < 0)\r
303         g.setColor(g.getColor().darker());\r
304 \r
305 \r
306       g.fillRect(x-3,y-3,6,6);\r
307       g.setColor(Color.red);\r
308     }\r
309 //    //Now the rectangle\r
310 //    if (rectx2 != -1 && recty2 != -1) {\r
311 //      g.setColor(Color.white);\r
312 //\r
313 //      g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);\r
314 //    }\r
315   }\r
316 \r
317   public Dimension minimumsize() {\r
318     return prefsize;\r
319   }\r
320 \r
321   public Dimension preferredsize() {\r
322     return prefsize;\r
323   }\r
324 \r
325   public void keyTyped(KeyEvent evt) { }\r
326   public void keyReleased(KeyEvent evt) { }\r
327 \r
328   public void keyPressed(KeyEvent evt) {\r
329     requestFocus();\r
330     if (evt.getKeyCode() == KeyEvent.VK_UP) {\r
331       scalefactor = (float)(scalefactor * 1.1);\r
332       scale = findScale();\r
333     } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) {\r
334       scalefactor = (float)(scalefactor * 0.9);\r
335       scale = findScale();\r
336     } else if (evt.getKeyChar() == 's') {\r
337       System.out.println("Rectangle selection");\r
338       if (rectx2 != -1 && recty2 != -1) {\r
339         rectSelect(rectx1,recty1,rectx2,recty2);\r
340 \r
341       }\r
342     }\r
343     repaint();\r
344   }\r
345 \r
346   public void printPoints() {\r
347     for (int i=0; i < npoint; i++) {\r
348       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
349       Format.print(System.out,"%5d ", i);\r
350       for (int j=0; j < 3;j++) {\r
351         Format.print(System.out,"%13.3f  ",sp.coord[j]);\r
352       }\r
353       System.out.println();\r
354     }\r
355   }\r
356 \r
357   public void mouseClicked(MouseEvent evt) { }\r
358   public void mouseEntered(MouseEvent evt) { }\r
359   public void mouseExited(MouseEvent evt) { }\r
360   public void mouseReleased(MouseEvent evt) { }\r
361 \r
362   public void mousePressed(MouseEvent evt) {\r
363     int x = evt.getX();\r
364     int y = evt.getY();\r
365 \r
366     mx = x;\r
367     my = y;\r
368 \r
369     omx = mx;\r
370     omy = my;\r
371 \r
372     startx = x;\r
373     starty = y;\r
374 \r
375     rectx1 = x;\r
376     recty1 = y;\r
377 \r
378     rectx2 = -1;\r
379     recty2 = -1;\r
380 \r
381     SequenceI found = findPoint(x,y);\r
382 \r
383     if (found != null)\r
384     {\r
385       if (av.getSelectionGroup() != null)\r
386       {\r
387         av.getSelectionGroup().addOrRemove(found);\r
388         PaintRefresher.Refresh(this);\r
389       }\r
390       else\r
391       {\r
392           av.setSelectionGroup(new SequenceGroup());\r
393           av.getSelectionGroup().addOrRemove(found);\r
394           av.getSelectionGroup().setEndRes(av.alignment.getWidth());\r
395 \r
396       }\r
397     }\r
398     repaint();\r
399   }\r
400 \r
401  // private void fireSequenceSelectionEvent(Selection sel) {\r
402  //   controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));\r
403   //}\r
404 \r
405   public void mouseMoved(MouseEvent evt)\r
406   {\r
407    SequenceI found = findPoint(evt.getX(), evt.getY());\r
408    if (found != null)\r
409      this.setToolTipText(found.getName());\r
410    else\r
411      this.setToolTipText(null);\r
412  }\r
413 \r
414   public void mouseDragged(MouseEvent evt) {\r
415     mx = evt.getX();\r
416     my = evt.getY();\r
417     //Check if this is a rectangle drawing drag\r
418     if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {\r
419 //      rectx2 = evt.getX();\r
420 //      recty2 = evt.getY();\r
421     } else {\r
422       rotmat.setIdentity();\r
423 \r
424       rotmat.rotate((float)(my-omy),'x');\r
425       rotmat.rotate((float)(mx-omx),'y');\r
426 \r
427       for (int i = 0; i < npoint; i++) {\r
428         SequencePoint sp = (SequencePoint)points.elementAt(i);\r
429         sp.coord[0] -= centre[0];\r
430         sp.coord[1] -= centre[1];\r
431         sp.coord[2] -= centre[2];\r
432 \r
433         //Now apply the rotation matrix\r
434         sp.coord= rotmat.vectorMultiply(sp.coord);\r
435 \r
436         //Now translate back again\r
437         sp.coord[0] += centre[0];\r
438         sp.coord[1] += centre[1];\r
439         sp.coord[2] += centre[2];\r
440       }\r
441 \r
442       for (int i=0; i < 3; i++) {\r
443         axes[i] = rotmat.vectorMultiply(axes[i]);\r
444       }\r
445       omx = mx;\r
446       omy = my;\r
447 \r
448       paint(this.getGraphics());\r
449     }\r
450 \r
451   }\r
452 \r
453   public void rectSelect(int x1, int y1, int x2, int y2) {\r
454     boolean changedSel = false;\r
455     for (int i=0; i < npoint; i++) {\r
456       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
457       int tmp1 = (int)((sp.coord[0] - centre[0])*scale + (float)getWidth()/2.0);\r
458       int tmp2 = (int)((sp.coord[1] - centre[1])*scale + (float)getHeight()/2.0);\r
459 \r
460       if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2) {\r
461         if (av != null) {\r
462           if (!av.getSelectionGroup().sequences.contains(sp.sequence))\r
463           {\r
464             changedSel = true;\r
465             av.getSelectionGroup().addSequence(sp.sequence);\r
466           }\r
467         }\r
468       }\r
469     }\r
470    // if (changedSel) {\r
471    //    fireSequenceSelectionEvent(av.getSelection());\r
472    // }\r
473   }\r
474   public SequenceI findPoint(int x, int y) {\r
475 \r
476     int halfwidth = getWidth()/2;\r
477     int halfheight = getHeight()/2;\r
478 \r
479     int found = -1;\r
480 \r
481     for (int i=0; i < npoint; i++) {\r
482 \r
483       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
484       int px = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;\r
485       int py = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;\r
486 \r
487 \r
488       if (Math.abs(px-x)<3 && Math.abs(py - y) < 3 ) {\r
489         found = i;\r
490       }\r
491     }\r
492     if (found != -1) {\r
493       return ((SequencePoint)points.elementAt(found)).sequence;\r
494     } else {\r
495       return null;\r
496     }\r
497   }\r
498 /*  public boolean handleRubberbandEvent(RubberbandEvent evt) {\r
499     System.out.println("Rubberband handler called in RotatableCanvas with " +\r
500                        evt.getBounds());\r
501 \r
502     Rubberband rb = (Rubberband)evt.getSource();\r
503 \r
504     // Clear the current selection (instance variable)\r
505     //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {\r
506     //   clearSelection();\r
507     //}\r
508 \r
509     if (rb.getComponent() == this) {\r
510       Rectangle bounds = evt.getBounds();\r
511       rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);\r
512     }\r
513 \r
514     redrawneeded = true;\r
515     paint(this.getGraphics());\r
516 \r
517     return true;\r
518   }*/\r
519 \r
520 }\r