2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
19 package jalview.gui;
\r
24 import java.awt.event.*;
\r
25 import javax.swing.*;
\r
27 import jalview.datamodel.*;
\r
28 import jalview.math.*;
\r
29 import jalview.util.*;
\r
31 public class RotatableCanvas
\r
32 extends JPanel implements MouseListener,
\r
33 MouseMotionListener, KeyListener
\r
34 //RubberbandListener,
\r
35 //SequenceSelectionListener
\r
37 RotatableMatrix idmat = new RotatableMatrix(3, 3);
\r
38 RotatableMatrix objmat = new RotatableMatrix(3, 3);
\r
39 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
\r
41 //RubberbandRectangle rubberband;
\r
42 boolean drawAxes = true;
\r
50 float[] centre = new float[3];
\r
51 float[] width = new float[3];
\r
52 float[] max = new float[3];
\r
53 float[] min = new float[3];
\r
68 float scalefactor = 1;
\r
71 // Controller controller;
\r
72 public RotatableCanvas(AlignViewport av, Vector points, int npoint)
\r
74 this.points = points;
\r
75 this.npoint = npoint;
\r
77 ToolTipManager.sharedInstance().registerComponent(this);
\r
78 PaintRefresher.Register(this, av.alignment);
\r
81 prefsize = getPreferredSize();
\r
82 orig = new float[npoint][3];
\r
84 for (int i = 0; i < npoint; i++)
\r
86 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
88 for (int j = 0; j < 3; j++)
\r
90 orig[i][j] = sp.coord[j];
\r
94 //Initialize the matrices to identity
\r
95 for (int i = 0; i < 3; i++)
\r
97 for (int j = 0; j < 3; j++)
\r
101 idmat.addElement(i, j, 0);
\r
102 objmat.addElement(i, j, 0);
\r
103 rotmat.addElement(i, j, 0);
\r
107 idmat.addElement(i, j, 0);
\r
108 objmat.addElement(i, j, 0);
\r
109 rotmat.addElement(i, j, 0);
\r
114 axes = new float[3][3];
\r
120 scale = findScale();
\r
122 // System.out.println("Scale factor = " + scale);
\r
123 addMouseListener(this);
\r
124 addKeyListener(this);
\r
126 // if (getParent() != null) {
\r
127 // getParent().addKeyListener(this);
\r
129 addMouseMotionListener(this);
\r
132 // rubberband = new RubberbandRectangle(this);
\r
133 // rubberband.setActive(true);
\r
134 // rubberband.addListener(this);
\r
137 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
138 redrawneeded = true;
\r
143 public void removeNotify() {
\r
144 controller.removeListener(this);
\r
145 super.removeNotify();
\r
147 public void initAxes()
\r
149 for (int i = 0; i < 3; i++)
\r
151 for (int j = 0; j < 3; j++)
\r
165 public void findWidth()
\r
167 max = new float[3];
\r
168 min = new float[3];
\r
170 max[0] = (float) - 1e30;
\r
171 max[1] = (float) - 1e30;
\r
172 max[2] = (float) - 1e30;
\r
174 min[0] = (float) 1e30;
\r
175 min[1] = (float) 1e30;
\r
176 min[2] = (float) 1e30;
\r
178 for (int i = 0; i < 3; i++)
\r
180 for (int j = 0; j < npoint; j++)
\r
182 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
184 if (sp.coord[i] >= max[i])
\r
186 max[i] = sp.coord[i];
\r
189 if (sp.coord[i] <= min[i])
\r
191 min[i] = sp.coord[i];
\r
196 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
197 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
198 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
199 width[0] = Math.abs(max[0] - min[0]);
\r
200 width[1] = Math.abs(max[1] - min[1]);
\r
201 width[2] = Math.abs(max[2] - min[2]);
\r
203 maxwidth = width[0];
\r
205 if (width[1] > width[0])
\r
207 maxwidth = width[1];
\r
210 if (width[2] > width[1])
\r
212 maxwidth = width[2];
\r
215 //System.out.println("Maxwidth = " + maxwidth);
\r
218 public float findScale()
\r
224 if (getWidth() != 0)
\r
226 width = getWidth();
\r
227 height = getHeight();
\r
231 width = prefsize.width;
\r
232 height = prefsize.height;
\r
235 if (width < height)
\r
244 return (float) ( (dim * scalefactor) / (2 * maxwidth));
\r
247 public void findCentre()
\r
249 //Find centre coordinate
\r
252 centre[0] = (max[0] + min[0]) / 2;
\r
253 centre[1] = (max[1] + min[1]) / 2;
\r
254 centre[2] = (max[2] + min[2]) / 2;
\r
256 // System.out.println("Centre x " + centre[0]);
\r
257 //System.out.println("Centre y " + centre[1]);
\r
258 //System.out.println("Centre z " + centre[2]);
\r
261 public Dimension getPreferredSize()
\r
263 if (prefsize != null)
\r
269 return new Dimension(400, 400);
\r
273 public Dimension getMinimumSize()
\r
275 return getPreferredSize();
\r
278 public void paintComponent(Graphics g)
\r
280 //Only create the image at the beginning -
\r
281 if ( (img == null) || (prefsize.width != getWidth()) ||
\r
282 (prefsize.height != getHeight()))
\r
284 prefsize.width = getWidth();
\r
285 prefsize.height = getHeight();
\r
287 scale = findScale();
\r
289 // System.out.println("New scale = " + scale);
\r
290 img = createImage(getWidth(), getHeight());
\r
291 ig = img.getGraphics();
\r
294 drawBackground(ig, Color.black);
\r
297 if (drawAxes == true)
\r
302 g.drawImage(img, 0, 0, this);
\r
305 public void drawAxes(Graphics g)
\r
307 g.setColor(Color.yellow);
\r
309 for (int i = 0; i < 3; i++)
\r
311 g.drawLine(getWidth() / 2, getHeight() / 2,
\r
312 (int) ( (axes[i][0] * scale * max[0]) + (getWidth() / 2)),
\r
313 (int) ( (axes[i][1] * scale * max[1]) + (getHeight() / 2)));
\r
317 public void drawBackground(Graphics g, Color col)
\r
320 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
323 public void drawScene(Graphics g)
\r
325 boolean darker = false;
\r
327 int halfwidth = getWidth() / 2;
\r
328 int halfheight = getHeight() / 2;
\r
330 for (int i = 0; i < npoint; i++)
\r
332 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
333 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) +
\r
335 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) +
\r
337 float z = sp.coord[1] - centre[2];
\r
339 if (sp.sequence.getColor() == Color.black)
\r
341 g.setColor(Color.white);
\r
345 g.setColor(sp.sequence.getColor());
\r
348 if (av.getSelectionGroup() != null)
\r
350 if (av.getSelectionGroup().sequences.contains(
\r
351 ( (SequencePoint) points.elementAt(i)).sequence))
\r
353 g.setColor(Color.gray);
\r
359 g.setColor(g.getColor().darker());
\r
362 g.fillRect(x - 3, y - 3, 6, 6);
\r
363 g.setColor(Color.red);
\r
366 // //Now the rectangle
\r
367 // if (rectx2 != -1 && recty2 != -1) {
\r
368 // g.setColor(Color.white);
\r
370 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
374 public Dimension minimumsize()
\r
379 public Dimension preferredsize()
\r
384 public void keyTyped(KeyEvent evt)
\r
388 public void keyReleased(KeyEvent evt)
\r
392 public void keyPressed(KeyEvent evt)
\r
396 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
398 scalefactor = (float) (scalefactor * 1.1);
\r
399 scale = findScale();
\r
401 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
403 scalefactor = (float) (scalefactor * 0.9);
\r
404 scale = findScale();
\r
406 else if (evt.getKeyChar() == 's')
\r
408 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
410 if ( (rectx2 != -1) && (recty2 != -1))
\r
412 rectSelect(rectx1, recty1, rectx2, recty2);
\r
419 public void printPoints()
\r
421 for (int i = 0; i < npoint; i++)
\r
423 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
424 Format.print(System.out, "%5d ", i);
\r
426 for (int j = 0; j < 3; j++)
\r
428 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
431 System.out.println();
\r
435 public void mouseClicked(MouseEvent evt)
\r
439 public void mouseEntered(MouseEvent evt)
\r
443 public void mouseExited(MouseEvent evt)
\r
447 public void mouseReleased(MouseEvent evt)
\r
451 public void mousePressed(MouseEvent evt)
\r
453 int x = evt.getX();
\r
454 int y = evt.getY();
\r
471 SequenceI found = findPoint(x, y);
\r
475 if (av.getSelectionGroup() != null)
\r
477 av.getSelectionGroup().addOrRemove(found, true);
\r
478 PaintRefresher.Refresh(this, av.alignment);
\r
482 av.setSelectionGroup(new SequenceGroup());
\r
483 av.getSelectionGroup().addOrRemove(found, true);
\r
484 av.getSelectionGroup().setEndRes(av.alignment.getWidth());
\r
491 // private void fireSequenceSelectionEvent(Selection sel) {
\r
492 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
494 public void mouseMoved(MouseEvent evt)
\r
496 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
500 this.setToolTipText(found.getName());
\r
504 this.setToolTipText(null);
\r
508 public void mouseDragged(MouseEvent evt)
\r
513 //Check if this is a rectangle drawing drag
\r
514 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
516 // rectx2 = evt.getX();
\r
517 // recty2 = evt.getY();
\r
521 rotmat.setIdentity();
\r
523 rotmat.rotate( (float) (my - omy), 'x');
\r
524 rotmat.rotate( (float) (mx - omx), 'y');
\r
526 for (int i = 0; i < npoint; i++)
\r
528 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
529 sp.coord[0] -= centre[0];
\r
530 sp.coord[1] -= centre[1];
\r
531 sp.coord[2] -= centre[2];
\r
533 //Now apply the rotation matrix
\r
534 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
536 //Now translate back again
\r
537 sp.coord[0] += centre[0];
\r
538 sp.coord[1] += centre[1];
\r
539 sp.coord[2] += centre[2];
\r
542 for (int i = 0; i < 3; i++)
\r
544 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
550 paint(this.getGraphics());
\r
554 public void rectSelect(int x1, int y1, int x2, int y2)
\r
556 boolean changedSel = false;
\r
558 for (int i = 0; i < npoint; i++)
\r
560 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
561 int tmp1 = (int) ( ( (sp.coord[0] - centre[0]) * scale) +
\r
562 ( (float) getWidth() / 2.0));
\r
563 int tmp2 = (int) ( ( (sp.coord[1] - centre[1]) * scale) +
\r
564 ( (float) getHeight() / 2.0));
\r
566 if ( (tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
\r
570 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
573 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
579 // if (changedSel) {
\r
580 // fireSequenceSelectionEvent(av.getSelection());
\r
584 public SequenceI findPoint(int x, int y)
\r
586 int halfwidth = getWidth() / 2;
\r
587 int halfheight = getHeight() / 2;
\r
591 for (int i = 0; i < npoint; i++)
\r
593 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
594 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) +
\r
596 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) +
\r
599 if ( (Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
\r
607 return ( (SequencePoint) points.elementAt(found)).sequence;
\r
615 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
616 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
619 Rubberband rb = (Rubberband)evt.getSource();
\r
621 // Clear the current selection (instance variable)
\r
622 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
623 // clearSelection();
\r
626 if (rb.getComponent() == this) {
\r
627 Rectangle bounds = evt.getBounds();
\r
628 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
631 redrawneeded = true;
\r
632 paint(this.getGraphics());
\r