Space changes
[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 != null)\r
298       {\r
299         if (av.getSelection().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       if (av != null) {\r
385 \r
386         if (av.getSelection().contains(found)) {\r
387           av.getSelection().removeElement(found);\r
388         } else {\r
389           av.getSelection().addElement(found);\r
390         }\r
391         PaintRefresher.Refresh(this);\r
392       }\r
393     }\r
394     repaint();\r
395   }\r
396 \r
397  // private void fireSequenceSelectionEvent(Selection sel) {\r
398  //   controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));\r
399   //}\r
400 \r
401   public void mouseMoved(MouseEvent evt)\r
402   {\r
403    SequenceI found = findPoint(evt.getX(), evt.getY());\r
404    if (found != null)\r
405      this.setToolTipText(found.getName());\r
406    else\r
407      this.setToolTipText(null);\r
408  }\r
409 \r
410   public void mouseDragged(MouseEvent evt) {\r
411     mx = evt.getX();\r
412     my = evt.getY();\r
413     //Check if this is a rectangle drawing drag\r
414     if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {\r
415 //      rectx2 = evt.getX();\r
416 //      recty2 = evt.getY();\r
417     } else {\r
418       rotmat.setIdentity();\r
419 \r
420       rotmat.rotate((float)(my-omy),'x');\r
421       rotmat.rotate((float)(mx-omx),'y');\r
422 \r
423       for (int i = 0; i < npoint; i++) {\r
424         SequencePoint sp = (SequencePoint)points.elementAt(i);\r
425         sp.coord[0] -= centre[0];\r
426         sp.coord[1] -= centre[1];\r
427         sp.coord[2] -= centre[2];\r
428 \r
429         //Now apply the rotation matrix\r
430         sp.coord= rotmat.vectorMultiply(sp.coord);\r
431 \r
432         //Now translate back again\r
433         sp.coord[0] += centre[0];\r
434         sp.coord[1] += centre[1];\r
435         sp.coord[2] += centre[2];\r
436       }\r
437 \r
438       for (int i=0; i < 3; i++) {\r
439         axes[i] = rotmat.vectorMultiply(axes[i]);\r
440       }\r
441       omx = mx;\r
442       omy = my;\r
443 \r
444       paint(this.getGraphics());\r
445     }\r
446 \r
447   }\r
448 \r
449   public void rectSelect(int x1, int y1, int x2, int y2) {\r
450     boolean changedSel = false;\r
451     for (int i=0; i < npoint; i++) {\r
452       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
453       int tmp1 = (int)((sp.coord[0] - centre[0])*scale + (float)getWidth()/2.0);\r
454       int tmp2 = (int)((sp.coord[1] - centre[1])*scale + (float)getHeight()/2.0);\r
455 \r
456       if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2) {\r
457         if (av != null) {\r
458           if (!av.getSelection().contains(sp.sequence)) {\r
459             changedSel = true;\r
460             av.getSelection().addElement(sp.sequence);\r
461           }\r
462         }\r
463       }\r
464     }\r
465    // if (changedSel) {\r
466    //    fireSequenceSelectionEvent(av.getSelection());\r
467    // }\r
468   }\r
469   public SequenceI findPoint(int x, int y) {\r
470 \r
471     int halfwidth = getWidth()/2;\r
472     int halfheight = getHeight()/2;\r
473 \r
474     int found = -1;\r
475 \r
476     for (int i=0; i < npoint; i++) {\r
477 \r
478       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
479       int px = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;\r
480       int py = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;\r
481 \r
482 \r
483       if (Math.abs(px-x)<3 && Math.abs(py - y) < 3 ) {\r
484         found = i;\r
485       }\r
486     }\r
487     if (found != -1) {\r
488       return ((SequencePoint)points.elementAt(found)).sequence;\r
489     } else {\r
490       return null;\r
491     }\r
492   }\r
493 /*  public boolean handleRubberbandEvent(RubberbandEvent evt) {\r
494     System.out.println("Rubberband handler called in RotatableCanvas with " +\r
495                        evt.getBounds());\r
496 \r
497     Rubberband rb = (Rubberband)evt.getSource();\r
498 \r
499     // Clear the current selection (instance variable)\r
500     //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {\r
501     //   clearSelection();\r
502     //}\r
503 \r
504     if (rb.getComponent() == this) {\r
505       Rectangle bounds = evt.getBounds();\r
506       rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);\r
507     }\r
508 \r
509     redrawneeded = true;\r
510     paint(this.getGraphics());\r
511 \r
512     return true;\r
513   }*/\r
514 \r
515 }\r