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