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