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