Return accurate RGB for transparent residues
[jalview.git] / src / jalview / appletgui / AnnotationPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 \r
27 import jalview.datamodel.*;\r
28 \r
29 public class AnnotationPanel\r
30     extends Panel implements AdjustmentListener\r
31 {\r
32   AlignViewport av;\r
33   AlignmentPanel ap;\r
34   int activeRow = -1;\r
35 \r
36   Vector activeRes;\r
37   static String HELIX = "Helix";\r
38   static String SHEET = "Sheet";\r
39   static String LABEL = "Label";\r
40   static String REMOVE = "Remove Annotation";\r
41   static String COLOUR = "Colour";\r
42   static Color HELIX_COLOUR = Color.red.darker();\r
43   static Color SHEET_COLOUR = Color.green.darker().darker();\r
44 \r
45   Image image;\r
46   Graphics gg;\r
47   FontMetrics fm;\r
48   int imgWidth = 0;\r
49 \r
50   boolean fastPaint = false;\r
51 \r
52   public static int GRAPH_HEIGHT = 40;\r
53 \r
54   public AnnotationPanel(AlignmentPanel ap)\r
55   {\r
56     this.ap = ap;\r
57     av = ap.av;\r
58     this.setLayout(null);\r
59     adjustPanelHeight();\r
60 \r
61     addMouseMotionListener(new MouseMotionAdapter()\r
62     {\r
63       public void mouseMoved(MouseEvent evt)\r
64       {\r
65         doMouseMoved(evt);\r
66       }\r
67     });\r
68 \r
69     // ap.annotationScroller.getVAdjustable().addAdjustmentListener( this );\r
70   }\r
71 \r
72 \r
73   public AnnotationPanel(AlignViewport av)\r
74   {\r
75     this.av = av;\r
76   }\r
77 \r
78 \r
79   public void adjustmentValueChanged(AdjustmentEvent evt)\r
80   {\r
81     ap.alabels.setScrollOffset( -evt.getValue());\r
82   }\r
83 \r
84   public int adjustPanelHeight()\r
85   {\r
86     // setHeight of panels\r
87     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
88 \r
89 \r
90     int height = 0;\r
91     if (aa != null)\r
92     {\r
93       for (int i = 0; i < aa.length; i++)\r
94       {\r
95         if (!aa[i].visible)\r
96         {\r
97           continue;\r
98         }\r
99 \r
100         aa[i].height = 0;\r
101 \r
102         if (aa[i].hasText)\r
103         {\r
104           aa[i].height += av.charHeight;\r
105         }\r
106         if (aa[i].hasIcons)\r
107         {\r
108           aa[i].height += 16;\r
109         }\r
110 \r
111         if (aa[i].isGraph)\r
112         {\r
113           aa[i].height += GRAPH_HEIGHT;\r
114         }\r
115 \r
116         if (aa[i].height == 0)\r
117         {\r
118           aa[i].height = 20;\r
119         }\r
120         height += aa[i].height;\r
121       }\r
122     }\r
123     else\r
124     {\r
125       height = 20;\r
126     }\r
127 \r
128     this.setSize(getSize().width, height);\r
129     if(ap!=null)\r
130        ap.annotationScroller.setSize(getSize().width, height);\r
131 \r
132 \r
133     repaint();\r
134 \r
135     return height;\r
136 \r
137   }\r
138 \r
139   public void addEditableColumn(int i)\r
140   {\r
141     if (activeRow == -1)\r
142     {\r
143       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
144       if(aa ==null)\r
145         return;\r
146 \r
147       for (int j = 0; j < aa.length; j++)\r
148       {\r
149         if (aa[j].editable)\r
150         {\r
151           activeRow = j;\r
152           break;\r
153         }\r
154       }\r
155     }\r
156 \r
157     if (activeRes == null)\r
158     {\r
159       activeRes = new Vector();\r
160       activeRes.addElement(String.valueOf(i));\r
161       return;\r
162     }\r
163 \r
164     activeRes.addElement(String.valueOf(i));\r
165   }\r
166 \r
167   public void doMouseMoved(MouseEvent evt)\r
168   {\r
169     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
170     if (aa == null)\r
171     {\r
172       return;\r
173     }\r
174 \r
175     int row = -1;\r
176     int height = 0;\r
177     for (int i = 0; i < aa.length; i++)\r
178     {\r
179 \r
180       if (aa[i].visible)\r
181       {\r
182         height += aa[i].height;\r
183       }\r
184 \r
185       if (evt.getY() < height)\r
186       {\r
187         row = i;\r
188         break;\r
189       }\r
190     }\r
191 \r
192     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
193     if (row > -1 && res < aa[row].annotations.length && aa[row].annotations[res] != null)\r
194     {\r
195       StringBuffer text = new StringBuffer("Sequence position " + (res + 1) +\r
196                                            "  " +\r
197                                            aa[row].annotations[res].description);\r
198       ap.alignFrame.statusBar.setText(text.toString());\r
199     }\r
200   }\r
201 \r
202   public void update(Graphics g)\r
203   {\r
204     paint(g);\r
205   }\r
206 \r
207   public void paint(Graphics g)\r
208   {\r
209     g.setColor(Color.white);\r
210     g.fillRect(0,0, getSize().width, getSize().height);\r
211     imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
212 \r
213     if (image == null || imgWidth != image.getWidth(this))\r
214     {\r
215       image = createImage(imgWidth, ap.annotationPanel.getSize().height);\r
216       gg = image.getGraphics();\r
217       gg.setFont(av.getFont());\r
218       fm = gg.getFontMetrics();\r
219       fastPaint = false;\r
220     }\r
221 \r
222     if (!jalview.bin.JalviewLite.AWT1)\r
223     {\r
224       MyGraphics.AntiAlias(gg);\r
225     }\r
226 \r
227 \r
228     if (fastPaint)\r
229     {\r
230       g.drawImage(image, 0, 0, this);\r
231       fastPaint = false;\r
232       return;\r
233     }\r
234 \r
235     drawComponent(gg, av.startRes, av.endRes + 1);\r
236     g.drawImage(image, 0, 0, this);\r
237   }\r
238 \r
239   public void fastPaint(int horizontal)\r
240   {\r
241     if (horizontal == 0\r
242         || av.alignment.getAlignmentAnnotation() == null\r
243         || av.alignment.getAlignmentAnnotation().length < 1\r
244         )\r
245     {\r
246       repaint();\r
247       return;\r
248     }\r
249 \r
250     gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal * av.charWidth, 0);\r
251     int sr = av.startRes, er = av.endRes + 1, transX = 0;\r
252 \r
253     if (horizontal > 0) // scrollbar pulled right, image to the left\r
254     {\r
255       transX = (er - sr - horizontal) * av.charWidth;\r
256       sr = er - horizontal;\r
257     }\r
258     else if (horizontal < 0)\r
259     {\r
260       er = sr - horizontal;\r
261     }\r
262 \r
263     gg.translate(transX, 0);\r
264 \r
265     drawComponent(gg, sr, er);\r
266 \r
267     gg.translate( -transX, 0);\r
268 \r
269     fastPaint = true;\r
270     repaint();\r
271   }\r
272 \r
273   public void drawComponent(Graphics g, int startRes, int endRes)\r
274   {\r
275     g.setFont(av.getFont());\r
276 \r
277     if (fm == null)\r
278       fm = g.getFontMetrics();\r
279 \r
280 \r
281       g.setColor(Color.white);\r
282       g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getSize().height);\r
283 \r
284       if ((av.alignment.getAlignmentAnnotation() == null) ||\r
285               (av.alignment.getAlignmentAnnotation().length < 1))\r
286       {\r
287           g.setColor(Color.white);\r
288           g.fillRect(0, 0, getSize().width, getSize().height);\r
289           g.setColor(Color.black);\r
290           g.drawString("Alignment has no annotations", 20, 15);\r
291 \r
292           return;\r
293       }\r
294 \r
295       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
296 \r
297       int j;\r
298       int x = 0;\r
299       int y = 0;\r
300       char[] lastSS = new char[aa.length];\r
301       int[] lastSSX = new int[aa.length];\r
302       int iconOffset = av.charHeight / 2;\r
303       boolean validRes = false;\r
304 \r
305       //\u03B2 \u03B1\r
306       for (int i = 0; i < aa.length; i++)\r
307       {\r
308           AlignmentAnnotation row = aa[i];\r
309 \r
310           if (!row.visible)\r
311           {\r
312               continue;\r
313           }\r
314 \r
315 \r
316           if (row.isGraph)\r
317           {\r
318               // this is so that we draw the characters below the graph\r
319               y += row.height;\r
320 \r
321               if (row.hasText)\r
322               {\r
323                   y -= av.charHeight;\r
324               }\r
325           }\r
326 \r
327           if (row.hasText)\r
328           {\r
329               iconOffset = av.charHeight / 2;\r
330           }\r
331           else\r
332           {\r
333               iconOffset = 0;\r
334           }\r
335 \r
336           for (j = startRes; j < endRes; j++)\r
337           {\r
338               if ((row.annotations.length <= j) ||\r
339                       (row.annotations[j] == null))\r
340               {\r
341                   validRes = false;\r
342               }\r
343               else\r
344               {\r
345                   validRes = true;\r
346               }\r
347 \r
348               x = (j - startRes) * av.charWidth;\r
349 \r
350 \r
351               if (validRes &&\r
352                       (row.annotations[j].displayCharacter.length() > 0))\r
353               {\r
354 \r
355                   int charOffset = (av.charWidth -\r
356                       fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
357                               0))) / 2;\r
358                   g.setColor(row.annotations[j].colour);\r
359 \r
360                   if (j == 0 || row.isGraph)\r
361                   {\r
362                       g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
363                           y + iconOffset + 3);\r
364                   }\r
365                   else if (((row.annotations[j - 1] == null) ||\r
366                           (row.annotations[j].displayCharacter != row.annotations[j -\r
367                           1].displayCharacter)))\r
368                   {\r
369                       g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
370                           y + iconOffset + 3);\r
371                   }\r
372               }\r
373 \r
374               if (row.hasIcons)\r
375               {\r
376                   if (!validRes ||\r
377                           (row.annotations[j].secondaryStructure != lastSS[i]))\r
378                   {\r
379                       switch (lastSS[i])\r
380                       {\r
381                       case 'H':\r
382                           g.setColor(HELIX_COLOUR);\r
383                           g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
384                               x - lastSSX[i], 7, 8, 8);\r
385 \r
386                           break;\r
387 \r
388                       case 'E':\r
389                           g.setColor(SHEET_COLOUR);\r
390                           g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
391                               x - lastSSX[i] - 4, 7);\r
392                           g.fillPolygon(new int[] { x - 4, x - 4, x },\r
393                               new int[]\r
394                               {\r
395                                   y + iconOffset, y + 14 + iconOffset,\r
396                                   y + 8 + iconOffset\r
397                               }, 3);\r
398 \r
399                           break;\r
400 \r
401                       case 'C':\r
402                           break;\r
403 \r
404                       default:\r
405                           g.setColor(Color.gray);\r
406                           g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
407                               x - lastSSX[i], 2);\r
408 \r
409                           break;\r
410                       }\r
411 \r
412                       if (validRes)\r
413                       {\r
414                           lastSS[i] = row.annotations[j].secondaryStructure;\r
415                       }\r
416                       else\r
417                       {\r
418                           lastSS[i] = ' ';\r
419                       }\r
420 \r
421                       lastSSX[i] = x;\r
422                   }\r
423               }\r
424 \r
425               if (validRes && row.isGraph)\r
426               {\r
427                   g.setColor(new Color(0, 0, 180));\r
428 \r
429                   int height = (int) ((row.annotations[j].value / row.graphMax) * GRAPH_HEIGHT);\r
430 \r
431                   if (row.windowLength > 1)\r
432                   {\r
433                       int total = 0;\r
434 \r
435                       for (int i2 = j - (row.windowLength / 2);\r
436                               i2 < (j + (row.windowLength / 2)); i2++)\r
437                       {\r
438                           if ((i2 < 0) || (i2 >= av.alignment.getWidth()))\r
439                           {\r
440                               continue;\r
441                           }\r
442 \r
443                           total += row.annotations[i2].value;\r
444                       }\r
445 \r
446                       total /= row.windowLength;\r
447                       height = (int) ((total / row.graphMax) * GRAPH_HEIGHT);\r
448                   }\r
449 \r
450                   g.setColor(row.annotations[j].colour);\r
451                   g.fillRect(x, y - height, av.charWidth, height);\r
452               }\r
453           }\r
454 \r
455           x += av.charWidth;\r
456 \r
457           if (row.hasIcons)\r
458           {\r
459               switch (lastSS[i])\r
460               {\r
461               case 'H':\r
462                   g.setColor(HELIX_COLOUR);\r
463                   g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
464                       x - lastSSX[i], 7, 8, 8);\r
465 \r
466                   break;\r
467 \r
468               case 'E':\r
469                   g.setColor(SHEET_COLOUR);\r
470                   g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
471                       x - lastSSX[i] - 4, 7);\r
472                   g.fillPolygon(new int[] { x - 4, x - 4, x },\r
473                       new int[]\r
474                       {\r
475                           y + iconOffset, y + 14 + iconOffset,\r
476                           y + 7 + iconOffset\r
477                       }, 3);\r
478 \r
479                   break;\r
480 \r
481               case 'C':\r
482                   break;\r
483 \r
484               default:\r
485                   g.setColor(Color.gray);\r
486                   g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
487 \r
488                   break;\r
489               }\r
490           }\r
491 \r
492           if (row.isGraph && row.hasText)\r
493           {\r
494               y += av.charHeight;\r
495           }\r
496 \r
497           if (!row.isGraph)\r
498           {\r
499               y += aa[i].height;\r
500           }\r
501         }\r
502   }\r
503 \r
504   // used by overview window\r
505   public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
506   {\r
507       g.setColor(Color.white);\r
508       g.fillRect(0, 0, width, y);\r
509       g.setColor(new Color(0, 0, 180));\r
510 \r
511       int x = 0, height;\r
512 \r
513       for (int j = sRes; j < eRes; j++)\r
514       {\r
515           g.setColor(new Color(0, 0, 180));\r
516 \r
517           height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);\r
518           if(height>y)\r
519               height = y;\r
520           g.fillRect(x, y - height, av.charWidth, height);\r
521           x += av.charWidth;\r
522       }\r
523     }\r
524 }\r