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