update author list in license for (JAL-826)
[jalview.git] / src / jalview / gui / ScalePanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, 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     }
82     else
83     {
84       res = x;
85     }
86
87     min = res;
88     max = res;
89
90     if (SwingUtilities.isRightMouseButton(evt))
91     {
92       JPopupMenu pop = new JPopupMenu();
93       if (reveal != null)
94       {
95         JMenuItem item = new JMenuItem("Reveal");
96         item.addActionListener(new ActionListener()
97         {
98           public void actionPerformed(ActionEvent e)
99           {
100             av.showColumn(reveal[0]);
101             reveal = null;
102             ap.paintAlignment(true);
103             if (ap.overviewPanel != null)
104             {
105               ap.overviewPanel.updateOverviewImage();
106             }
107           }
108         });
109         pop.add(item);
110
111         if (av.getColumnSelection().getHiddenColumns().size() > 1)
112         {
113           item = new JMenuItem("Reveal All");
114           item.addActionListener(new ActionListener()
115           {
116             public void actionPerformed(ActionEvent e)
117             {
118               av.showAllHiddenColumns();
119               reveal = null;
120               ap.paintAlignment(true);
121               if (ap.overviewPanel != null)
122               {
123                 ap.overviewPanel.updateOverviewImage();
124               }
125             }
126           });
127           pop.add(item);
128         }
129         pop.show(this, evt.getX(), evt.getY());
130       }
131       else if (av.getColumnSelection().contains(res))
132       {
133         JMenuItem item = new JMenuItem("Hide Columns");
134         item.addActionListener(new ActionListener()
135         {
136           public void actionPerformed(ActionEvent e)
137           {
138             av.hideColumns(res, res);
139             if (av.getSelectionGroup() != null
140                     && av.getSelectionGroup().getSize() == av.alignment
141                             .getHeight())
142             {
143               av.setSelectionGroup(null);
144             }
145
146             ap.paintAlignment(true);
147             if (ap.overviewPanel != null)
148             {
149               ap.overviewPanel.updateOverviewImage();
150             }
151           }
152         });
153         pop.add(item);
154         pop.show(this, evt.getX(), evt.getY());
155       }
156     }
157     else
158     // LEFT MOUSE TO SELECT
159     {
160       if (!evt.isControlDown() && !evt.isShiftDown())
161       {
162         av.getColumnSelection().clear();
163       }
164
165       av.getColumnSelection().addElement(res);
166       SequenceGroup sg = new SequenceGroup();
167       // try to be as quick as possible
168       SequenceI[] iVec = av.alignment.getSequencesArray();
169       for (int i = 0; i < iVec.length; i++)
170       {
171         sg.addSequence(iVec[i], false);
172         iVec[i] = null;
173       }
174       iVec = null;
175       sg.setStartRes(res);
176       sg.setEndRes(res);
177
178       if (evt.isShiftDown())
179       {
180         int min = Math.min(av.getColumnSelection().getMin(), res);
181         int max = Math.max(av.getColumnSelection().getMax(), res);
182         for (int i = min; i < max; i++)
183         {
184           av.getColumnSelection().addElement(i);
185         }
186         sg.setStartRes(min);
187         sg.setEndRes(max);
188       }
189       av.setSelectionGroup(sg);
190     }
191
192     ap.paintAlignment(false);
193     av.sendSelection();
194   }
195
196   /**
197    * DOCUMENT ME!
198    * 
199    * @param evt
200    *          DOCUMENT ME!
201    */
202   public void mouseReleased(MouseEvent evt)
203   {
204     mouseDragging = false;
205
206     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
207
208     if (av.hasHiddenColumns)
209     {
210       res = av.getColumnSelection().adjustForHiddenColumns(res);
211     }
212
213     if (res >= av.alignment.getWidth())
214     {
215       res = av.alignment.getWidth() - 1;
216     }
217
218     if (!stretchingGroup)
219     {
220       ap.paintAlignment(false);
221
222       return;
223     }
224
225     SequenceGroup sg = av.getSelectionGroup();
226
227     if (sg != null)
228     {
229       if (res > sg.getStartRes())
230       {
231         sg.setEndRes(res);
232       }
233       else if (res < sg.getStartRes())
234       {
235         sg.setStartRes(res);
236       }
237     }
238     stretchingGroup = false;
239     ap.paintAlignment(false);
240     av.sendSelection();
241   }
242
243   /**
244    * DOCUMENT ME!
245    * 
246    * @param evt
247    *          DOCUMENT ME!
248    */
249   public void mouseDragged(MouseEvent evt)
250   {
251     mouseDragging = true;
252
253     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
254     if (res < 0)
255     {
256       res = 0;
257     }
258
259     if (av.hasHiddenColumns)
260     {
261       res = av.getColumnSelection().adjustForHiddenColumns(res);
262     }
263
264     if (res >= av.alignment.getWidth())
265     {
266       res = av.alignment.getWidth() - 1;
267     }
268
269     if (res < min)
270     {
271       min = res;
272     }
273
274     if (res > max)
275     {
276       max = res;
277     }
278
279     SequenceGroup sg = av.getSelectionGroup();
280
281     if (sg != null)
282     {
283       stretchingGroup = true;
284
285       if (!av.getColumnSelection().contains(res))
286       {
287         av.getColumnSelection().addElement(res);
288       }
289
290       if (res > sg.getStartRes())
291       {
292         sg.setEndRes(res);
293       }
294       if (res < sg.getStartRes())
295       {
296         sg.setStartRes(res);
297       }
298
299       int col;
300       for (int i = min; i <= max; i++)
301       {
302         col = i; // av.getColumnSelection().adjustForHiddenColumns(i);
303
304         if ((col < sg.getStartRes()) || (col > sg.getEndRes()))
305         {
306           av.getColumnSelection().removeElement(col);
307         }
308         else
309         {
310           av.getColumnSelection().addElement(col);
311         }
312       }
313
314       ap.paintAlignment(false);
315     }
316   }
317
318   public void mouseEntered(MouseEvent evt)
319   {
320     if (mouseDragging)
321     {
322       ap.seqPanel.scrollCanvas(null);
323     }
324   }
325
326   public void mouseExited(MouseEvent evt)
327   {
328     if (mouseDragging)
329     {
330       ap.seqPanel.scrollCanvas(evt);
331     }
332   }
333
334   public void mouseClicked(MouseEvent evt)
335   {
336   }
337
338   public void mouseMoved(MouseEvent evt)
339   {
340     if (!av.hasHiddenColumns)
341     {
342       return;
343     }
344
345     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
346
347     res = av.getColumnSelection().adjustForHiddenColumns(res);
348
349     reveal = null;
350     for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size(); i++)
351     {
352       int[] region = (int[]) av.getColumnSelection().getHiddenColumns()
353               .elementAt(i);
354       if (res + 1 == region[0] || res - 1 == region[1])
355       {
356         reveal = region;
357         ToolTipManager.sharedInstance().registerComponent(this);
358         this.setToolTipText("Reveal Hidden Columns with Right Mouse Button");
359         break;
360       }
361       else
362       {
363         this.setToolTipText(null);
364       }
365
366     }
367
368     repaint();
369   }
370
371   int[] reveal;
372
373   /**
374    * DOCUMENT ME!
375    * 
376    * @param g
377    *          DOCUMENT ME!
378    */
379   public void paintComponent(Graphics g)
380   {
381     drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
382   }
383
384   // scalewidth will normally be screenwidth,
385   public void drawScale(Graphics g, int startx, int endx, int width,
386           int height)
387   {
388     Graphics2D gg = (Graphics2D) g;
389     gg.setFont(av.getFont());
390
391     if (av.antiAlias)
392     {
393       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
394               RenderingHints.VALUE_ANTIALIAS_ON);
395     }
396
397     // Fill in the background
398     gg.setColor(Color.white);
399     gg.fillRect(0, 0, width, height);
400     gg.setColor(Color.black);
401
402     // Fill the selected columns
403     ColumnSelection cs = av.getColumnSelection();
404     int s;
405     if (cs != null)
406     {
407       gg.setColor(new Color(220, 0, 0));
408
409       for (int i = 0; i < cs.size(); i++)
410       {
411         int sel = cs.columnAt(i);
412         if (av.hasHiddenColumns)
413         {
414           if (cs.isVisible(sel))
415           {
416             sel = cs.findColumnPosition(sel);
417           }
418           else
419           {
420             continue;
421           }
422         }
423
424         if ((sel >= startx) && (sel <= endx))
425         {
426           gg.fillRect((sel - startx) * av.charWidth, 0, av.charWidth,
427                   getHeight());
428         }
429       }
430     }
431     // Draw the scale numbers
432     gg.setColor(Color.black);
433
434     int scalestartx = (startx / 10) * 10;
435
436     FontMetrics fm = gg.getFontMetrics(av.getFont());
437     int y = av.charHeight - fm.getDescent();
438
439     if ((scalestartx % 10) == 0)
440     {
441       scalestartx += 5;
442     }
443
444     String string;
445     int maxX = 0;
446
447     for (int i = scalestartx; i < endx; i += 5)
448     {
449       if ((i % 10) == 0)
450       {
451         string = String.valueOf(av.getColumnSelection()
452                 .adjustForHiddenColumns(i));
453         if ((i - startx - 1) * av.charWidth > maxX)
454         {
455           gg.drawString(string, (i - startx - 1) * av.charWidth, y);
456           maxX = (i - startx + 1) * av.charWidth + fm.stringWidth(string);
457         }
458
459         gg.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.drawLine(
469                 (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
470                 y + fm.getDescent(),
471                 (int) (((i - startx - 1) * av.charWidth) + (av.charWidth / 2)),
472                 y + (fm.getDescent() * 2));
473       }
474     }
475
476     if (av.hasHiddenColumns)
477     {
478       gg.setColor(Color.blue);
479       int res;
480       if (av.getShowHiddenMarkers())
481       {
482         for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
483                 .size(); i++)
484         {
485
486           res = av.getColumnSelection().findHiddenRegionPosition(i)
487                   - startx;
488
489           if (res < 0 || res > endx - scalestartx)
490           {
491             continue;
492           }
493
494           gg.fillPolygon(new int[]
495           { res * av.charWidth - av.charHeight / 4,
496               res * av.charWidth + av.charHeight / 4, res * av.charWidth },
497                   new int[]
498                   { y - av.charHeight / 2, y - av.charHeight / 2, y + 8 },
499                   3);
500
501         }
502       }
503
504       if (reveal != null && reveal[0] > startx && reveal[0] < endx)
505       {
506         gg.drawString("Reveal Columns", reveal[0] * av.charWidth, 0);
507       }
508     }
509
510   }
511 }