resizeAgain flag set if user resizes whilst image is being prepared
[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 = 30;\r
36   int boxX = -1, boxY = -1, boxWidth = -1, boxHeight = -1;\r
37 \r
38   boolean resizing = false;\r
39 \r
40   Frame nullFrame;\r
41 \r
42   public OverviewPanel(AlignmentPanel ap)\r
43   {\r
44     this.av = ap.av;\r
45     this.ap = ap;\r
46     setLayout(null);\r
47     nullFrame = new Frame();\r
48     nullFrame.addNotify();\r
49 \r
50     // scale the initial size of overviewpanel to shape of alignment\r
51     float initialScale = (float) av.alignment.getWidth() /\r
52         (float) av.alignment.getHeight();\r
53     if (av.alignment.getWidth() > av.alignment.getHeight())\r
54     {\r
55       // wider\r
56       width = 400;\r
57       sequencesHeight = (int) (400f / initialScale);\r
58     }\r
59     else\r
60     {\r
61       // taller\r
62       width = (int) (400f * initialScale);\r
63       sequencesHeight = 300;\r
64       if (width < 120)\r
65       {\r
66         width = 120;\r
67       }\r
68     }\r
69 \r
70     setSize(new Dimension(width, sequencesHeight + graphHeight));\r
71     addComponentListener(new ComponentAdapter()\r
72     {\r
73 \r
74       public void componentResized(ComponentEvent evt)\r
75       {\r
76         if (getSize().width != width ||\r
77             getSize().height != sequencesHeight + graphHeight)\r
78         {\r
79           updateOverviewImage();\r
80         }\r
81       }\r
82     });\r
83 \r
84     addMouseMotionListener(new MouseMotionAdapter()\r
85     {\r
86       public void mouseDragged(MouseEvent evt)\r
87       {\r
88         doMouseDragged(evt);\r
89       }\r
90     });\r
91 \r
92     addMouseListener(new MouseAdapter()\r
93     {\r
94       public void mousePressed(MouseEvent evt)\r
95       {\r
96         doMousePressed(evt);\r
97       }\r
98 \r
99       public void mouseReleased(MouseEvent evt)\r
100       {\r
101         doMouseReleased(evt);\r
102       }\r
103     });\r
104 \r
105     updateOverviewImage();\r
106 \r
107   }\r
108 \r
109   public void doMousePressed(MouseEvent evt)\r
110   {\r
111     boxX = evt.getX();\r
112     boxY = evt.getY();\r
113 \r
114     checkValid();\r
115     repaint();\r
116   }\r
117 \r
118   public void doMouseReleased(MouseEvent evt)\r
119   {\r
120     boxX = evt.getX();\r
121     boxY = evt.getY();\r
122     checkValid();\r
123     if (!resizing)\r
124     {\r
125       ap.setScrollValues( (int) (boxX / scalew / av.getCharWidth()),\r
126                          (int) (boxY / scaleh / av.getCharHeight()));\r
127     }\r
128   }\r
129 \r
130   public void doMouseDragged(MouseEvent evt)\r
131   {\r
132     boxX = evt.getX();\r
133     boxY = evt.getY();\r
134     checkValid();\r
135     if (!resizing)\r
136     {\r
137       ap.setScrollValues( (int) (boxX / scalew / av.getCharWidth()),\r
138                          (int) (boxY / scaleh / av.getCharHeight()));\r
139     }\r
140     repaint();\r
141     ap.repaint();\r
142   }\r
143 \r
144   void checkValid()\r
145   {\r
146     if (boxY < 0)\r
147     {\r
148       boxY = 0;\r
149     }\r
150 \r
151     if (boxY > sequencesHeight - boxHeight)\r
152     {\r
153       boxY = sequencesHeight - boxHeight + 1;\r
154     }\r
155 \r
156     if (boxX < 0)\r
157     {\r
158       boxX = 0;\r
159     }\r
160 \r
161     if (boxX > width - boxWidth)\r
162     {\r
163       boxX = width - boxWidth;\r
164     }\r
165   }\r
166 \r
167   /**\r
168    * DOCUMENT ME!\r
169    */\r
170   public void updateOverviewImage()\r
171   {\r
172       if (resizing)\r
173       {\r
174           resizeAgain = true;\r
175           return;\r
176       }\r
177 \r
178       resizing = true;\r
179 \r
180       Thread thread = new Thread(this);\r
181       thread.start();\r
182       repaint();\r
183   }\r
184 \r
185   // This is set true if the user resizes whilst\r
186   // the overview is being calculated\r
187     boolean resizeAgain = false;\r
188 \r
189   public void run()\r
190   {\r
191     miniMe = null;\r
192     int alwidth = av.alignment.getWidth();\r
193     int alheight = av.alignment.getHeight();\r
194 \r
195     if (getSize().width > 0 && getSize().height > 0)\r
196     {\r
197       width = getSize().width;\r
198       sequencesHeight = getSize().height - graphHeight;\r
199     }\r
200 \r
201     setSize(new Dimension(width, sequencesHeight + graphHeight));\r
202 \r
203     int fullsizeWidth = alwidth * av.getCharWidth();\r
204     int fullsizeHeight = alheight * av.getCharHeight();\r
205 \r
206     scalew = (float) width / (float) fullsizeWidth;\r
207     scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
208 \r
209     miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight);\r
210 \r
211     Graphics mg = miniMe.getGraphics();\r
212     Image consensus = nullFrame.createImage(fullsizeWidth, 60);\r
213     Graphics g = consensus.getGraphics();\r
214     ap.annotationPanel.drawGraph(g, av.conservation, fullsizeWidth, 60);\r
215     mg.drawImage(consensus, 0, sequencesHeight, width,\r
216                  sequencesHeight + graphHeight, 0, 0, fullsizeWidth, 60, this);\r
217 \r
218     boolean oldRenderGaps = av.renderGaps;\r
219     try\r
220     {\r
221       // We'll have to draw the full size alignment in chunks, as an image of the\r
222       // whole alignment requires too much memory\r
223 \r
224       // Max size depends on the font size, the following is a\r
225       // guess at a size which works\r
226       int maxSize = 2000 / av.getFont().getSize();\r
227       Image block;\r
228       int blockx = 0, blocky = 0, blockw = 0, blockh = 0, eRes = 0, eSeq = 0;\r
229 \r
230       av.setRenderGaps(false);\r
231       for (int sRes = 0, chunkx = 0; sRes < alwidth; sRes += maxSize, chunkx++)\r
232       {\r
233         eSeq = 0;\r
234         eRes += maxSize;\r
235         if (eRes > alwidth)\r
236         {\r
237           eRes = alwidth;\r
238         }\r
239 \r
240         for (int sSeq = 0, chunky = 0; sSeq < alheight; sSeq += maxSize, chunky++)\r
241         {\r
242           if(resizeAgain)\r
243                   break;\r
244 \r
245           eSeq += maxSize;\r
246           if (eSeq > alheight)\r
247           {\r
248             eSeq = alheight;\r
249           }\r
250 \r
251           blocky = 0;\r
252           blockx = (int) ( (float) sRes / (float) alwidth * width);\r
253 \r
254           block = nullFrame.createImage( (eRes - sRes) * av.charWidth,\r
255                                         (eSeq - sSeq) * av.charHeight);\r
256           g = block.getGraphics();\r
257 \r
258           ap.seqPanel.seqCanvas.drawPanel(g, sRes, eRes, sSeq, eSeq, sRes, sSeq,\r
259                                           0);\r
260 \r
261           blockh = (int) ( (float) (eSeq - sSeq) / (float) alheight *\r
262                           sequencesHeight) + 1;\r
263           blockw = (int) ( (float) (eRes - sRes) / (float) alwidth * width) + 1;\r
264 \r
265           blocky += (int) ( (float) sSeq / (float) alheight * sequencesHeight);\r
266 \r
267           mg.drawImage(block, blockx,\r
268                        blocky,\r
269                        blockx + blockw,\r
270                        blocky + blockh,\r
271 \r
272                        0, 0, block.getWidth(null), block.getHeight(null), this);\r
273 \r
274           block = null;\r
275         }\r
276 \r
277       }\r
278 \r
279     }\r
280     catch (OutOfMemoryError error)\r
281     {\r
282       System.err.println(\r
283           "Out of memory when trying to calculate the overview window image!");\r
284     }\r
285 \r
286     System.gc();\r
287 \r
288     av.setRenderGaps(oldRenderGaps);\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   public void setBoxPosition()\r
301   {\r
302     boxX = (int) (av.getStartRes() * av.getCharWidth() * scalew);\r
303     boxY = (int) (av.getStartSeq() * av.getCharHeight() * scaleh);\r
304     boxWidth = (int) ( (av.getEndRes() - av.getStartRes() + 1) *\r
305                       av.getCharWidth() * scalew);\r
306     boxHeight = (int) (av.getEndSeq() * av.getCharHeight() * scaleh) - boxY;\r
307     repaint();\r
308   }\r
309 \r
310   public void update(Graphics g)\r
311   {\r
312     paint(g);\r
313   }\r
314 \r
315   public void paint(Graphics g)\r
316   {\r
317     if (resizing)\r
318     {\r
319       g.setColor(Color.white);\r
320       g.fillRect(0, 0, getSize().width, getSize().height);\r
321       g.setColor(Color.black);\r
322 \r
323       g.setFont(new Font("Verdana", Font.BOLD, 15));\r
324       g.drawString("Recalculating", 5, sequencesHeight / 2);\r
325       g.drawString("Overview.....", 5, sequencesHeight / 2 + 20);\r
326     }\r
327     else\r
328     {\r
329       if (miniMe != null)\r
330       {\r
331         g.drawImage(miniMe, 0, 0, this);\r
332       }\r
333 \r
334       g.setColor(Color.red);\r
335       g.drawRect(boxX, boxY, boxWidth, boxHeight);\r
336       g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);\r
337     }\r
338   }\r
339 \r
340 }\r