Formatted source
[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   public void updateOverviewImage()\r
168   {\r
169     if (resizing)\r
170     {\r
171       return;\r
172     }\r
173 \r
174     resizing = true;\r
175     Thread thread = new Thread(this);\r
176     thread.start();\r
177     repaint();\r
178   }\r
179 \r
180   public void run()\r
181   {\r
182     miniMe = null;\r
183     int alwidth = av.alignment.getWidth();\r
184     int alheight = av.alignment.getHeight();\r
185 \r
186     if (getSize().width > 0 && getSize().height > 0)\r
187     {\r
188       width = getSize().width;\r
189       sequencesHeight = getSize().height - graphHeight;\r
190     }\r
191 \r
192     setSize(new Dimension(width, sequencesHeight + graphHeight));\r
193 \r
194     int fullsizeWidth = alwidth * av.getCharWidth();\r
195     int fullsizeHeight = alheight * av.getCharHeight();\r
196 \r
197     scalew = (float) width / (float) fullsizeWidth;\r
198     scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
199 \r
200     miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight);\r
201 \r
202     Graphics mg = miniMe.getGraphics();\r
203     Image consensus = nullFrame.createImage(fullsizeWidth, 60);\r
204     Graphics g = consensus.getGraphics();\r
205     ap.annotationPanel.drawGraph(g, av.conservation, fullsizeWidth, 60);\r
206     mg.drawImage(consensus, 0, sequencesHeight, width,\r
207                  sequencesHeight + graphHeight, 0, 0, fullsizeWidth, 60, this);\r
208 \r
209     boolean oldRenderGaps = av.renderGaps;\r
210     try\r
211     {\r
212       // We'll have to draw the full size alignment in chunks, as an image of the\r
213       // whole alignment requires too much memory\r
214 \r
215       // Max size depends on the font size, the following is a\r
216       // guess at a size which works\r
217       int maxSize = 2000 / av.getFont().getSize();\r
218       Image block;\r
219       int blockx = 0, blocky = 0, blockw = 0, blockh = 0, eRes = 0, eSeq = 0;\r
220 \r
221       av.setRenderGaps(false);\r
222       for (int sRes = 0, chunkx = 0; sRes < alwidth; sRes += maxSize, chunkx++)\r
223       {\r
224         eSeq = 0;\r
225         eRes += maxSize;\r
226         if (eRes > alwidth)\r
227         {\r
228           eRes = alwidth;\r
229         }\r
230 \r
231         for (int sSeq = 0, chunky = 0; sSeq < alheight; sSeq += maxSize, chunky++)\r
232         {\r
233           eSeq += maxSize;\r
234           if (eSeq > alheight)\r
235           {\r
236             eSeq = alheight;\r
237           }\r
238 \r
239           blocky = 0;\r
240           blockx = (int) ( (float) sRes / (float) alwidth * width);\r
241 \r
242           block = nullFrame.createImage( (eRes - sRes) * av.charWidth,\r
243                                         (eSeq - sSeq) * av.charHeight);\r
244           g = block.getGraphics();\r
245 \r
246           ap.seqPanel.seqCanvas.drawPanel(g, sRes, eRes, sSeq, eSeq, sRes, sSeq,\r
247                                           0);\r
248 \r
249           blockh = (int) ( (float) (eSeq - sSeq) / (float) alheight *\r
250                           sequencesHeight) + 1;\r
251           blockw = (int) ( (float) (eRes - sRes) / (float) alwidth * width) + 1;\r
252 \r
253           blocky += (int) ( (float) sSeq / (float) alheight * sequencesHeight);\r
254 \r
255           mg.drawImage(block, blockx,\r
256                        blocky,\r
257                        blockx + blockw,\r
258                        blocky + blockh,\r
259 \r
260                        0, 0, block.getWidth(null), block.getHeight(null), this);\r
261 \r
262           block = null;\r
263         }\r
264 \r
265       }\r
266 \r
267     }\r
268     catch (OutOfMemoryError error)\r
269     {\r
270       System.err.println(\r
271           "Out of memory when trying to calculate the overview window image!");\r
272     }\r
273 \r
274     av.setRenderGaps(oldRenderGaps);\r
275     resizing = false;\r
276 \r
277     setBoxPosition();\r
278   }\r
279 \r
280   public void setBoxPosition()\r
281   {\r
282     boxX = (int) (av.getStartRes() * av.getCharWidth() * scalew);\r
283     boxY = (int) (av.getStartSeq() * av.getCharHeight() * scaleh);\r
284     boxWidth = (int) ( (av.getEndRes() - av.getStartRes() + 1) *\r
285                       av.getCharWidth() * scalew);\r
286     boxHeight = (int) (av.getEndSeq() * av.getCharHeight() * scaleh) - boxY;\r
287     repaint();\r
288   }\r
289 \r
290   public void update(Graphics g)\r
291   {\r
292     paint(g);\r
293   }\r
294 \r
295   public void paint(Graphics g)\r
296   {\r
297     if (resizing)\r
298     {\r
299       g.setColor(Color.white);\r
300       g.fillRect(0, 0, getSize().width, getSize().height);\r
301       g.setColor(Color.black);\r
302 \r
303       g.setFont(new Font("Verdana", Font.BOLD, 15));\r
304       g.drawString("Recalculating", 5, sequencesHeight / 2);\r
305       g.drawString("Overview.....", 5, sequencesHeight / 2 + 20);\r
306     }\r
307     else\r
308     {\r
309       if (miniMe != null)\r
310       {\r
311         g.drawImage(miniMe, 0, 0, this);\r
312       }\r
313 \r
314       g.setColor(Color.red);\r
315       g.drawRect(boxX, boxY, boxWidth, boxHeight);\r
316       g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);\r
317     }\r
318   }\r
319 \r
320 }\r