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