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