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