Control and shift for col selection
[jalview.git] / src / jalview / gui / ScalePanel.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 jalview.datamodel.*;\r
22 \r
23 import java.awt.*;\r
24 import java.awt.event.*;\r
25 \r
26 import javax.swing.*;\r
27 \r
28 \r
29 /**\r
30  * DOCUMENT ME!\r
31  *\r
32  * @author $author$\r
33  * @version $Revision$\r
34  */\r
35 public class ScalePanel extends JPanel implements MouseMotionListener, MouseListener\r
36 {\r
37     protected int offy = 4;\r
38 \r
39     /** DOCUMENT ME!! */\r
40     public int width;\r
41     protected AlignViewport av;\r
42     AlignmentPanel ap;\r
43     boolean stretchingGroup = false;\r
44     int min; //used by mouseDragged to see if user\r
45     int max; //used by mouseDragged to see if user\r
46     boolean mouseDragging = false;\r
47 \r
48     // wants to delete columns\r
49     public ScalePanel(AlignViewport av, AlignmentPanel ap)\r
50     {\r
51         this.av = av;\r
52         this.ap = ap;\r
53 \r
54         addMouseListener(this);\r
55         addMouseMotionListener(this);\r
56     }\r
57 \r
58     /**\r
59      * DOCUMENT ME!\r
60      *\r
61      * @param evt DOCUMENT ME!\r
62      */\r
63     public void mousePressed(MouseEvent evt)\r
64     {\r
65         int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
66         final int res;\r
67 \r
68         if(av.hasHiddenColumns)\r
69           res = av.getColumnSelection().adjustForHiddenColumns(x);\r
70         else\r
71           res = x;\r
72 \r
73         min = res;\r
74         max = res;\r
75 \r
76         if (SwingUtilities.isRightMouseButton(evt))\r
77         {\r
78           JPopupMenu pop = new JPopupMenu();\r
79           if (reveal != null)\r
80           {\r
81             JMenuItem item = new JMenuItem("Reveal");\r
82             item.addActionListener(new ActionListener()\r
83             {\r
84               public void actionPerformed(ActionEvent e)\r
85               {\r
86                 av.showColumn(reveal[0]);\r
87                 reveal = null;\r
88                 ap.repaint();\r
89                 if (ap.overviewPanel != null)\r
90                   ap.overviewPanel.updateOverviewImage();\r
91               }\r
92             });\r
93             pop.add(item);\r
94 \r
95             if (av.getColumnSelection().getHiddenColumns().size() > 1)\r
96             {\r
97               item = new JMenuItem("Reveal All");\r
98               item.addActionListener(new ActionListener()\r
99               {\r
100                 public void actionPerformed(ActionEvent e)\r
101                 {\r
102                   av.showAllHiddenColumns();\r
103                   reveal = null;\r
104                   ap.repaint();\r
105                   if (ap.overviewPanel != null)\r
106                     ap.overviewPanel.updateOverviewImage();\r
107                 }\r
108               });\r
109               pop.add(item);\r
110             }\r
111             pop.show(this, evt.getX(), evt.getY());\r
112           }\r
113           else if (av.getColumnSelection().contains(res))\r
114           {\r
115             JMenuItem item = new JMenuItem("Hide Columns");\r
116             item.addActionListener(new ActionListener()\r
117             {\r
118               public void actionPerformed(ActionEvent e)\r
119               {\r
120                 av.hideColumns(res, res);\r
121                 ap.repaint();\r
122                 if (ap.overviewPanel != null)\r
123                   ap.overviewPanel.updateOverviewImage();\r
124               }\r
125             });\r
126             pop.add(item);\r
127             pop.show(this, evt.getX(), evt.getY());\r
128           }\r
129         }\r
130         else // LEFT MOUSE TO SELECT\r
131         {\r
132           if (!evt.isControlDown() && !evt.isShiftDown())\r
133           {\r
134             av.getColumnSelection().clear();\r
135           }\r
136 \r
137           av.getColumnSelection().addElement(res);\r
138           SequenceGroup sg = new SequenceGroup();\r
139           for (int i = 0; i < av.alignment.getSequences().size(); i++)\r
140           {\r
141             sg.addSequence(av.alignment.getSequenceAt(i), false);\r
142           }\r
143 \r
144           sg.setStartRes(res);\r
145           sg.setEndRes(res);\r
146           av.setSelectionGroup(sg);\r
147 \r
148           if(evt.isShiftDown())\r
149           {\r
150             int min = Math.min(av.getColumnSelection().getMin(), res);\r
151             int max = Math.max(av.getColumnSelection().getMax(), res);\r
152             for (int i = min; i<max; i++)\r
153             {\r
154                 av.getColumnSelection().addElement(i);\r
155             }\r
156             sg.setStartRes(min);\r
157             sg.setEndRes(max);\r
158           }\r
159 \r
160 \r
161         }\r
162 \r
163 \r
164         ap.repaint();\r
165     }\r
166 \r
167     /**\r
168      * DOCUMENT ME!\r
169      *\r
170      * @param evt DOCUMENT ME!\r
171      */\r
172     public void mouseReleased(MouseEvent evt)\r
173     {\r
174         mouseDragging = false;\r
175 \r
176         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
177 \r
178         if(res> av.alignment.getWidth())\r
179         {\r
180           res = av.alignment.getWidth()-1;\r
181         }\r
182 \r
183         if(av.hasHiddenColumns)\r
184           res = av.getColumnSelection().adjustForHiddenColumns(res);\r
185 \r
186         if (!stretchingGroup)\r
187         {\r
188             ap.repaint();\r
189 \r
190             return;\r
191         }\r
192 \r
193         SequenceGroup sg = av.getSelectionGroup();\r
194 \r
195         if (res > sg.getStartRes())\r
196         {\r
197             sg.setEndRes(res);\r
198         }\r
199         else if (res < sg.getStartRes())\r
200         {\r
201             sg.setStartRes(res);\r
202         }\r
203 \r
204         stretchingGroup = false;\r
205         ap.repaint();\r
206     }\r
207 \r
208     /**\r
209      * DOCUMENT ME!\r
210      *\r
211      * @param evt DOCUMENT ME!\r
212      */\r
213     public void mouseDragged(MouseEvent evt)\r
214     {\r
215         mouseDragging = true;\r
216 \r
217         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
218         if(res<0)\r
219           res = 0;\r
220 \r
221         if(av.hasHiddenColumns)\r
222           res = av.getColumnSelection().adjustForHiddenColumns(res);\r
223 \r
224 \r
225         if(res> av.alignment.getWidth())\r
226         {\r
227           res = av.alignment.getWidth()-1;\r
228         }\r
229 \r
230         if (res < min)\r
231         {\r
232             min = res;\r
233         }\r
234 \r
235         if (res > max)\r
236         {\r
237             max = res;\r
238         }\r
239 \r
240 \r
241 \r
242         SequenceGroup sg = av.getSelectionGroup();\r
243 \r
244         if (sg != null)\r
245         {\r
246             stretchingGroup = true;\r
247 \r
248             if (!av.getColumnSelection().contains(res))\r
249             {\r
250                 av.getColumnSelection().addElement(res);\r
251             }\r
252 \r
253             if (res > sg.getStartRes())\r
254             {\r
255                 sg.setEndRes(res);\r
256             }\r
257             if (res < sg.getStartRes())\r
258             {\r
259                 sg.setStartRes(res);\r
260             }\r
261 \r
262             for (int i = min; i <= max; i++)\r
263             {\r
264                 if ((i < sg.getStartRes()) || (i > sg.getEndRes()))\r
265                 {\r
266                     av.getColumnSelection().removeElement(i);\r
267                 }\r
268                 else\r
269                 {\r
270                     av.getColumnSelection().addElement(i);\r
271                 }\r
272             }\r
273 \r
274             ap.repaint();\r
275         }\r
276     }\r
277 \r
278     public void mouseEntered(MouseEvent evt)\r
279     {\r
280       if(mouseDragging)\r
281         ap.seqPanel.scrollCanvas(null);\r
282     }\r
283 \r
284     public void mouseExited(MouseEvent evt)\r
285     {\r
286       if(mouseDragging)\r
287         ap.seqPanel.scrollCanvas(evt);\r
288     }\r
289 \r
290     public void mouseClicked(MouseEvent evt){}\r
291 \r
292     public void mouseMoved(MouseEvent evt)\r
293     {\r
294       if(!av.hasHiddenColumns)\r
295         return;\r
296 \r
297       int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
298 \r
299       res = av.getColumnSelection().adjustForHiddenColumns(res);\r
300 \r
301       reveal = null;\r
302       for(int i=0; i<av.getColumnSelection().getHiddenColumns().size(); i++)\r
303       {\r
304         int [] region = (int[])av.getColumnSelection().getHiddenColumns().elementAt(i);\r
305         if(res+1==region[0] || res-1==region[1])\r
306         {\r
307           reveal = region;\r
308           ToolTipManager.sharedInstance().registerComponent(this);\r
309           this.setToolTipText("Reveal Hidden Columns with Right Mouse Button");\r
310           break;\r
311         }\r
312         else\r
313           this.setToolTipText(null);\r
314 \r
315       }\r
316 \r
317       repaint();\r
318     }\r
319 \r
320     int [] reveal;\r
321 \r
322     /**\r
323      * DOCUMENT ME!\r
324      *\r
325      * @param g DOCUMENT ME!\r
326      */\r
327     public void paintComponent(Graphics g)\r
328     {\r
329         drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());\r
330     }\r
331 \r
332     // scalewidth will normally be screenwidth,\r
333     public void drawScale(Graphics g, int startx, int endx, int width,\r
334         int height)\r
335     {\r
336         Graphics2D gg = (Graphics2D) g;\r
337         gg.setFont(av.getFont());\r
338 \r
339         if(av.antiAlias)\r
340           gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
341                               RenderingHints.VALUE_ANTIALIAS_ON);\r
342 \r
343         //Fill in the background\r
344         gg.setColor(Color.white);\r
345         gg.fillRect(0, 0, width, height);\r
346         gg.setColor(Color.black);\r
347 \r
348         //Fill the selected columns\r
349         ColumnSelection cs = av.getColumnSelection();\r
350         gg.setColor(new Color(220, 0, 0));\r
351 \r
352         for (int i = 0; i < cs.size(); i++)\r
353         {\r
354             int sel = cs.columnAt(i);\r
355             if(av.hasHiddenColumns)\r
356                 sel = av.getColumnSelection().findColumnPosition(sel);\r
357 \r
358             if ((sel >= startx) && (sel <= endx))\r
359             {\r
360                 gg.fillRect((sel - startx) * av.charWidth, 0, av.charWidth,\r
361                     getHeight());\r
362             }\r
363         }\r
364 \r
365         // Draw the scale numbers\r
366         gg.setColor(Color.black);\r
367 \r
368         int scalestartx = (startx / 10) * 10;\r
369 \r
370         FontMetrics fm = gg.getFontMetrics(av.getFont());\r
371         int y = av.charHeight - fm.getDescent();\r
372 \r
373         if ((scalestartx % 10) == 0)\r
374         {\r
375             scalestartx += 5;\r
376         }\r
377 \r
378         String string;\r
379         int maxX=0;\r
380 \r
381         for (int i = scalestartx; i < endx; i += 5)\r
382         {\r
383             if ((i % 10) == 0)\r
384             {\r
385                 string = String.valueOf(av.getColumnSelection().adjustForHiddenColumns(i));\r
386                 if ( (i - startx - 1) * av.charWidth > maxX)\r
387                 {\r
388                   gg.drawString(string,\r
389                                 (i - startx - 1) * av.charWidth, y);\r
390                   maxX = (i - startx + 1) * av.charWidth + fm.stringWidth(string);\r
391                 }\r
392 \r
393                 gg.drawLine( (int) ( ( (i - startx - 1) * av.charWidth) +\r
394                                     (av.charWidth / 2)), y + 2,\r
395                             (int) ( ( (i - startx - 1) * av.charWidth) +\r
396                                    (av.charWidth / 2)),\r
397                             y + (fm.getDescent() * 2));\r
398 \r
399             }\r
400             else\r
401             {\r
402                 gg.drawLine((int) (((i - startx - 1) * av.charWidth) +\r
403                     (av.charWidth / 2)), y + fm.getDescent(),\r
404                     (int) (((i - startx - 1) * av.charWidth) +\r
405                     (av.charWidth / 2)), y + (fm.getDescent() * 2));\r
406             }\r
407         }\r
408 \r
409         if (av.hasHiddenColumns)\r
410         {\r
411           gg.setColor(Color.blue);\r
412           int res;\r
413           if(av.getShowHiddenMarkers())\r
414           {\r
415             for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size();\r
416                  i++)\r
417             {\r
418 \r
419               res = av.getColumnSelection().findHiddenRegionPosition(i) -\r
420                   startx;\r
421 \r
422               if(res < 0 || res > endx-scalestartx)\r
423                 continue;\r
424 \r
425               gg.fillPolygon(new int[]\r
426                              {res * av.charWidth - av.charHeight / 4,\r
427                              res * av.charWidth + av.charHeight / 4,\r
428                              res * av.charWidth},\r
429                              new int[]\r
430                              {\r
431                              y - av.charHeight / 2, y - av.charHeight / 2,\r
432                              y + 8\r
433               }, 3);\r
434 \r
435             }\r
436           }\r
437 \r
438           if (reveal != null && reveal[0] > startx && reveal[0] < endx)\r
439           {\r
440             gg.drawString("Reveal Columns", reveal[0] * av.charWidth, 0);\r
441           }\r
442         }\r
443 \r
444 \r
445     }\r
446 }\r