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