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