4dfb8c8aebb9f2ba071558816932dea3d44501ec
[jalview.git] / src / jalview / gui / ScalePanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.awt.*;
22 import java.awt.event.*;
23 import javax.swing.*;
24
25 import jalview.datamodel.*;
26
27 /**
28  * DOCUMENT ME!
29  * 
30  * @author $author$
31  * @version $Revision$
32  */
33 public class ScalePanel extends JPanel implements MouseMotionListener,
34         MouseListener
35 {
36   protected int offy = 4;
37
38   /** DOCUMENT ME!! */
39   public int width;
40
41   protected AlignViewport av;
42
43   AlignmentPanel ap;
44
45   boolean stretchingGroup = false;
46
47   int min; // used by mouseDragged to see if user
48
49   int max; // used by mouseDragged to see if user
50
51   boolean mouseDragging = false;
52
53   // wants to delete columns
54   public ScalePanel(AlignViewport av, AlignmentPanel ap)
55   {
56     this.av = av;
57     this.ap = ap;
58
59     addMouseListener(this);
60     addMouseMotionListener(this);
61   }
62
63   /**
64    * DOCUMENT ME!
65    * 
66    * @param evt
67    *                DOCUMENT ME!
68    */
69   public void mousePressed(MouseEvent evt)
70   {
71     int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
72     final int res;
73
74     if (av.hasHiddenColumns)
75     {
76       res = av.getColumnSelection().adjustForHiddenColumns(x);
77     }
78     else
79     {
80       res = x;
81     }
82
83     min = res;
84     max = res;
85
86     if (SwingUtilities.isRightMouseButton(evt))
87     {
88       JPopupMenu pop = new JPopupMenu();
89       if (reveal != null)
90       {
91         JMenuItem item = new JMenuItem("Reveal");
92         item.addActionListener(new ActionListener()
93         {
94           public void actionPerformed(ActionEvent e)
95           {
96             av.showColumn(reveal[0]);
97             reveal = null;
98             ap.paintAlignment(true);
99             if (ap.overviewPanel != null)
100             {
101               ap.overviewPanel.updateOverviewImage();
102             }
103           }
104         });
105         pop.add(item);
106
107         if (av.getColumnSelection().getHiddenColumns().size() > 1)
108         {
109           item = new JMenuItem("Reveal All");
110           item.addActionListener(new ActionListener()
111           {
112             public void actionPerformed(ActionEvent e)
113             {
114               av.showAllHiddenColumns();
115               reveal = null;
116               ap.paintAlignment(true);
117               if (ap.overviewPanel != null)
118               {
119                 ap.overviewPanel.updateOverviewImage();
120               }
121             }
122           });
123           pop.add(item);
124         }
125         pop.show(this, evt.getX(), evt.getY());
126       }
127       else if (av.getColumnSelection().contains(res))
128       {
129         JMenuItem item = new JMenuItem("Hide Columns");
130         item.addActionListener(new ActionListener()
131         {
132           public void actionPerformed(ActionEvent e)
133           {
134             av.hideColumns(res, res);
135             if (av.getSelectionGroup() != null
136                     && av.getSelectionGroup().getSize() == av.alignment
137                             .getHeight())
138             {
139               av.setSelectionGroup(null);
140             }
141
142             ap.paintAlignment(true);
143             if (ap.overviewPanel != null)
144             {
145               ap.overviewPanel.updateOverviewImage();
146             }
147           }
148         });
149         pop.add(item);
150         pop.show(this, evt.getX(), evt.getY());
151       }
152     }
153     else
154     // LEFT MOUSE TO SELECT
155     {
156       if (!evt.isControlDown() && !evt.isShiftDown())
157       {
158         av.getColumnSelection().clear();
159       }
160
161       av.getColumnSelection().addElement(res);
162       SequenceGroup sg = new SequenceGroup();
163       // try to be as quick as possible
164       SequenceI[] iVec = av.alignment.getSequencesArray();
165       for (int i = 0; i < iVec.length; i++)
166       {
167         sg.addSequence(iVec[i], false);
168         iVec[i] = null;
169       }
170       iVec = null;
171       sg.setStartRes(res);
172       sg.setEndRes(res);
173       av.setSelectionGroup(sg);
174
175       if (evt.isShiftDown())
176       {
177         int min = Math.min(av.getColumnSelection().getMin(), res);
178         int max = Math.max(av.getColumnSelection().getMax(), res);
179         for (int i = min; i < max; i++)
180         {
181           av.getColumnSelection().addElement(i);
182         }
183         sg.setStartRes(min);
184         sg.setEndRes(max);
185       }
186
187     }
188
189     ap.paintAlignment(false);
190   }
191
192   /**
193    * DOCUMENT ME!
194    * 
195    * @param evt
196    *                DOCUMENT ME!
197    */
198   public void mouseReleased(MouseEvent evt)
199   {
200     mouseDragging = false;
201
202     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
203
204     if (res > av.alignment.getWidth())
205     {
206       res = av.alignment.getWidth() - 1;
207     }
208
209     if (av.hasHiddenColumns)
210     {
211       res = av.getColumnSelection().adjustForHiddenColumns(res);
212     }
213
214     if (!stretchingGroup)
215     {
216       ap.paintAlignment(false);
217
218       return;
219     }
220
221     SequenceGroup sg = av.getSelectionGroup();
222
223     if (sg != null)
224     {
225       if (res > sg.getStartRes())
226       {
227         sg.setEndRes(res);
228       }
229       else if (res < sg.getStartRes())
230       {
231         sg.setStartRes(res);
232       }
233     }
234     stretchingGroup = false;
235     ap.paintAlignment(false);
236   }
237
238   /**
239    * DOCUMENT ME!
240    * 
241    * @param evt
242    *                DOCUMENT ME!
243    */
244   public void mouseDragged(MouseEvent evt)
245   {
246     mouseDragging = true;
247
248     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
249     if (res < 0)
250     {
251       res = 0;
252     }
253
254     if (av.hasHiddenColumns)
255     {
256       res = av.getColumnSelection().adjustForHiddenColumns(res);
257     }
258
259     if (res > av.alignment.getWidth())
260     {
261       res = av.alignment.getWidth() - 1;
262     }
263
264     if (res < min)
265     {
266       min = res;
267     }
268
269     if (res > max)
270     {
271       max = res;
272     }
273
274     SequenceGroup sg = av.getSelectionGroup();
275
276     if (sg != null)
277     {
278       stretchingGroup = true;
279
280       if (!av.getColumnSelection().contains(res))
281       {
282         av.getColumnSelection().addElement(res);
283       }
284
285       if (res > sg.getStartRes())
286       {
287         sg.setEndRes(res);
288       }
289       if (res < sg.getStartRes())
290       {
291         sg.setStartRes(res);
292       }
293
294       int col;
295       for (int i = min; i <= max; i++)
296       {
297         col = av.getColumnSelection().adjustForHiddenColumns(i);
298
299         if ((col < sg.getStartRes()) || (col > sg.getEndRes()))
300         {
301           av.getColumnSelection().removeElement(col);
302         }
303         else
304         {
305           av.getColumnSelection().addElement(col);
306         }
307       }
308
309       ap.paintAlignment(false);
310     }
311   }
312
313   public void mouseEntered(MouseEvent evt)
314   {
315     if (mouseDragging)
316     {
317       ap.seqPanel.scrollCanvas(null);
318     }
319   }
320
321   public void mouseExited(MouseEvent evt)
322   {
323     if (mouseDragging)
324     {
325       ap.seqPanel.scrollCanvas(evt);
326     }
327   }
328
329   public void mouseClicked(MouseEvent evt)
330   {
331   }
332
333   public void mouseMoved(MouseEvent evt)
334   {
335     if (!av.hasHiddenColumns)
336     {
337       return;
338     }
339
340     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
341
342     res = av.getColumnSelection().adjustForHiddenColumns(res);
343
344     reveal = null;
345     for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
346     {
347       int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
348               .elementAt(i);
349       if (res + 1 == region[0] || res - 1 == region[1])
350       {
351         reveal = region;
352         ToolTipManager.sharedInstance().registerComponent(this);
353         this
354                 .setToolTipText("Reveal Hidden Columns with Right Mouse Button");
355         break;
356       }
357       else
358       {
359         this.setToolTipText(null);
360       }
361
362     }
363
364     repaint();
365   }
366
367   int[] reveal;
368
369   /**
370    * DOCUMENT ME!
371    * 
372    * @param g
373    *                DOCUMENT ME!
374    */
375   public void paintComponent(Graphics g)
376   {
377     drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
378   }
379
380   // scalewidth will normally be screenwidth,
381   public void drawScale(Graphics g, int startx, int endx, int width,
382           int height)
383   {
384     Graphics2D gg = (Graphics2D) g;
385     gg.setFont(av.getFont());
386
387     if (av.antiAlias)
388     {
389       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
390               RenderingHints.VALUE_ANTIALIAS_ON);
391     }
392
393     // Fill in the background
394     gg.setColor(Color.white);
395     gg.fillRect(0, 0, width, height);
396     gg.setColor(Color.black);
397
398     // Fill the selected columns
399     ColumnSelection cs = av.getColumnSelection();
400     gg.setColor(new Color(220, 0, 0));
401
402     for (int i = 0; i < cs.size(); i++)
403     {
404       int sel = cs.columnAt(i);
405       if (av.hasHiddenColumns)
406       {
407         sel = av.getColumnSelection().findColumnPosition(sel);
408       }
409
410       if ((sel >= startx) && (sel <= endx))
411       {
412         gg.fillRect((sel - startx) * av.charWidth, 0, av.charWidth,
413                 getHeight());
414       }
415     }
416
417     // Draw the scale numbers
418     gg.setColor(Color.black);
419
420     int scalestartx = (startx / 10) * 10;
421
422     FontMetrics fm = gg.getFontMetrics(av.getFont());
423     int y = av.charHeight - fm.getDescent();
424
425     if ((scalestartx % 10) == 0)
426     {
427       scalestartx += 5;
428     }
429
430     String string;
431     int maxX = 0;
432
433     for (int i = scalestartx; i < endx; i += 5)
434     {
435       if ((i % 10) == 0)
436       {
437         string = String.valueOf(av.getColumnSelection()
438                 .adjustForHiddenColumns(i));
439         if ((i - startx - 1) * av.charWidth > maxX)
440         {
441           gg.drawString(string, (i - startx - 1) * av.charWidth, y);
442           maxX = (i - startx + 1) * av.charWidth + fm.stringWidth(string);
443         }
444
445         gg
446                 .drawLine(
447                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
448                         y + 2,
449                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
450                         y + (fm.getDescent() * 2));
451
452       }
453       else
454       {
455         gg
456                 .drawLine(
457                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
458                         y + fm.getDescent(),
459                         (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
460                         y + (fm.getDescent() * 2));
461       }
462     }
463
464     if (av.hasHiddenColumns)
465     {
466       gg.setColor(Color.blue);
467       int res;
468       if (av.getShowHiddenMarkers())
469       {
470         for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
471                 .size(); i++)
472         {
473
474           res = av.getColumnSelection().findHiddenRegionPosition(i)
475                   - startx;
476
477           if (res < 0 || res > endx - scalestartx)
478           {
479             continue;
480           }
481
482           gg.fillPolygon(new int[]
483           { res * av.charWidth - av.charHeight / 4,
484               res * av.charWidth + av.charHeight / 4, res * av.charWidth },
485                   new int[]
486                   { y - av.charHeight / 2, y - av.charHeight / 2, y + 8 },
487                   3);
488
489         }
490       }
491
492       if (reveal != null && reveal[0] > startx && reveal[0] < endx)
493       {
494         gg.drawString("Reveal Columns", reveal[0] * av.charWidth, 0);
495       }
496     }
497
498   }
499 }