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