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