Overview subsamples alignment
[jalview.git] / src / jalview / gui / OverviewPanel.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 package jalview.gui;\r
20 \r
21 import java.awt.*;\r
22 import java.awt.event.*;\r
23 import java.awt.image.*;\r
24 \r
25 import javax.swing.*;\r
26 \r
27 \r
28 /**\r
29  * DOCUMENT ME!\r
30  *\r
31  * @author $author$\r
32  * @version $Revision$\r
33  */\r
34 public class OverviewPanel extends JPanel implements Runnable\r
35 {\r
36     BufferedImage miniMe;\r
37     AlignViewport av;\r
38     AlignmentPanel ap;\r
39     float scalew = 1f;\r
40     float scaleh = 1f;\r
41     int width;\r
42     int sequencesHeight;\r
43     int graphHeight = 20;\r
44     int boxX = -1;\r
45     int boxY = -1;\r
46     int boxWidth = -1;\r
47     int boxHeight = -1;\r
48     boolean resizing = false;\r
49 \r
50     // Can set different properties in this seqCanvas than\r
51     // main visible SeqCanvas\r
52     SeqCanvas overviewSeq;\r
53 \r
54     /**\r
55      * Creates a new OverviewPanel object.\r
56      *\r
57      * @param ap DOCUMENT ME!\r
58      */\r
59     public OverviewPanel(AlignmentPanel ap)\r
60     {\r
61         this.av = ap.av;\r
62         this.ap = ap;\r
63         setLayout(null);\r
64 \r
65         overviewSeq = new SeqCanvas(av);\r
66         overviewSeq.isOverview = true;\r
67         overviewSeq.sr.renderGaps = false;\r
68 \r
69         // scale the initial size of overviewpanel to shape of alignment\r
70         float initialScale = (float) av.alignment.getWidth() / (float) av.alignment.getHeight();\r
71 \r
72         if(av.vconsensus==null)\r
73           graphHeight = 0;\r
74 \r
75 \r
76         if (av.alignment.getWidth() > av.alignment.getHeight())\r
77         {\r
78             // wider\r
79             width = 400;\r
80             sequencesHeight = (int) (400f / initialScale);\r
81             if(sequencesHeight<40)\r
82               sequencesHeight = 40;\r
83         }\r
84         else\r
85         {\r
86             // taller\r
87             width = (int) (400f * initialScale);\r
88             sequencesHeight = 300;\r
89 \r
90             if (width < 120)\r
91             {\r
92                 width = 120;\r
93             }\r
94         }\r
95 \r
96         addComponentListener(new ComponentAdapter()\r
97             {\r
98                 public void componentResized(ComponentEvent evt)\r
99                 {\r
100                     if ((getWidth() != width) ||\r
101                             (getHeight() != (sequencesHeight + graphHeight)))\r
102                     {\r
103                         updateOverviewImage();\r
104                     }\r
105                 }\r
106             });\r
107 \r
108         addMouseMotionListener(new MouseMotionAdapter()\r
109             {\r
110                 public void mouseDragged(MouseEvent evt)\r
111                 {\r
112                     doMouseDragged(evt);\r
113                 }\r
114             });\r
115 \r
116         addMouseListener(new MouseAdapter()\r
117             {\r
118                 public void mousePressed(MouseEvent evt)\r
119                 {\r
120                     doMousePressed(evt);\r
121                 }\r
122 \r
123                 public void mouseReleased(MouseEvent evt)\r
124                 {\r
125                     doMouseReleased(evt);\r
126                 }\r
127             });\r
128 \r
129         updateOverviewImage();\r
130     }\r
131 \r
132     /**\r
133      * DOCUMENT ME!\r
134      *\r
135      * @param evt DOCUMENT ME!\r
136      */\r
137     public void doMousePressed(MouseEvent evt)\r
138     {\r
139         boxX = evt.getX();\r
140         boxY = evt.getY();\r
141 \r
142         checkValid();\r
143         repaint();\r
144     }\r
145 \r
146     /**\r
147      * DOCUMENT ME!\r
148      *\r
149      * @param evt DOCUMENT ME!\r
150      */\r
151     public void doMouseReleased(MouseEvent evt)\r
152     {\r
153         boxX = evt.getX();\r
154         boxY = evt.getY();\r
155         checkValid();\r
156 \r
157         ap.setScrollValues((int) (boxX / scalew / av.getCharWidth()),\r
158                 (int) (boxY / scaleh / av.getCharHeight()));\r
159     }\r
160 \r
161     /**\r
162      * DOCUMENT ME!\r
163      *\r
164      * @param evt DOCUMENT ME!\r
165      */\r
166     public void doMouseDragged(MouseEvent evt)\r
167     {\r
168         boxX = evt.getX();\r
169         boxY = evt.getY();\r
170         checkValid();\r
171 \r
172         ap.setScrollValues( (int) (boxX / scalew / av.getCharWidth()),\r
173                            (int) (boxY / scaleh / av.getCharHeight()));\r
174        repaint();\r
175     }\r
176 \r
177     /**\r
178      * DOCUMENT ME!\r
179      */\r
180     void checkValid()\r
181     {\r
182         if (boxY < 0)\r
183         {\r
184             boxY = 0;\r
185         }\r
186 \r
187         if (boxY > (sequencesHeight - boxHeight))\r
188         {\r
189             boxY = sequencesHeight - boxHeight + 1;\r
190         }\r
191 \r
192         if (boxX < 0)\r
193         {\r
194             boxX = 0;\r
195         }\r
196 \r
197         if (boxX > (width - boxWidth))\r
198         {\r
199             boxX = width - boxWidth;\r
200         }\r
201     }\r
202 \r
203     /**\r
204      * DOCUMENT ME!\r
205      */\r
206     public void updateOverviewImage()\r
207     {\r
208         if (resizing)\r
209         {\r
210             resizeAgain = true;\r
211             return;\r
212         }\r
213 \r
214         resizing = true;\r
215 \r
216         if ( (getWidth() > 0) && (getHeight() > 0))\r
217         {\r
218           width = getWidth();\r
219           sequencesHeight = getHeight() - graphHeight;\r
220         }\r
221 \r
222         setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));\r
223         setBoxPosition();\r
224 \r
225         Thread thread = new Thread(this);\r
226         thread.start();\r
227         repaint();\r
228     }\r
229 \r
230     // This is set true if the user resizes whilst\r
231     // the overview is being calculated\r
232     boolean resizeAgain = false;\r
233 \r
234     /**\r
235      * DOCUMENT ME!\r
236      */\r
237     public void run()\r
238     {\r
239         miniMe = null;\r
240 \r
241         int alwidth = av.alignment.getWidth();\r
242         int alheight = av.alignment.getHeight();\r
243 \r
244         setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));\r
245 \r
246         int fullsizeWidth = alwidth * av.getCharWidth();\r
247         int fullsizeHeight = alheight * av.getCharHeight();\r
248 \r
249         scalew = (float) width / (float) fullsizeWidth;\r
250         scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
251 \r
252         miniMe = new BufferedImage(width, sequencesHeight + graphHeight,\r
253                 BufferedImage.TYPE_INT_RGB);\r
254 \r
255 \r
256         Graphics mg = miniMe.getGraphics();\r
257 \r
258         float sampleCol = (float) alwidth / (float) width;\r
259         float sampleRow = (float) alheight / (float) sequencesHeight;\r
260 \r
261         for (int col = 0; col < width; col++)\r
262         {\r
263           for (int row = 0; row < sequencesHeight; row++)\r
264           {\r
265             overviewSeq.drawPanel(mg,\r
266                                             (int) (col * sampleCol),\r
267                                             (int) (col * sampleCol),\r
268                                             (int) (row * sampleRow),\r
269                                             (int) (row * sampleRow) + 1,\r
270                                             (int) (col * sampleCol),\r
271                                             (int) (row * sampleRow), 0);\r
272             mg.translate(0, 1);\r
273 \r
274             if (av.conservation != null)\r
275               ap.annotationPanel.drawGraph(mg, av.conservation,\r
276                                            (int) (sampleCol) + 1,\r
277                                            graphHeight,\r
278                                            (int) (col * sampleCol),\r
279                                            (int) (col * sampleCol) + 1);\r
280 \r
281           }\r
282           mg.translate(0, -sequencesHeight);\r
283           mg.translate(1, 0);\r
284 \r
285         }\r
286 \r
287         System.gc();\r
288 \r
289         resizing = false;\r
290 \r
291         setBoxPosition();\r
292 \r
293         if(resizeAgain)\r
294         {\r
295           resizeAgain = false;\r
296           updateOverviewImage();\r
297         }\r
298     }\r
299 \r
300     /**\r
301      * DOCUMENT ME!\r
302      */\r
303     public void setBoxPosition()\r
304     {\r
305       int fullsizeWidth = av.alignment.getWidth() * av.getCharWidth();\r
306       int fullsizeHeight = av.alignment.getHeight() * av.getCharHeight();\r
307 \r
308       scalew = (float) width / (float) fullsizeWidth;\r
309       scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
310 \r
311         boxX = (int) (av.getStartRes() * av.getCharWidth() * scalew);\r
312         boxY = (int) (av.getStartSeq() * av.getCharHeight() * scaleh);\r
313         boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1) * av.getCharWidth() * scalew);\r
314         boxHeight = (int) (av.getEndSeq() * av.getCharHeight() * scaleh) -\r
315             boxY;\r
316         repaint();\r
317     }\r
318 \r
319     /**\r
320      * DOCUMENT ME!\r
321      *\r
322      * @param g DOCUMENT ME!\r
323      */\r
324     public void paintComponent(Graphics g)\r
325     {\r
326         if (miniMe != null && !resizing)\r
327         {\r
328           g.drawImage(miniMe, 0, 0, this);\r
329         }\r
330         else\r
331         {\r
332           g.setColor(Color.white);\r
333           g.fillRect(0, 0, getWidth(), getHeight());\r
334           g.setColor(Color.black);\r
335           g.setFont(new Font("Verdana", Font.BOLD, 15));\r
336           g.drawString("Recalculating", 5, sequencesHeight / 2);\r
337           g.drawString("Overview.....", 5, (sequencesHeight / 2) + 20);\r
338         }\r
339 \r
340 \r
341         g.setColor(Color.red);\r
342         g.drawRect(boxX, boxY, boxWidth, boxHeight);\r
343         g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);\r
344 \r
345     }\r
346 }\r