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 ToolTipManager.sharedInstance().setInitialDelay(0);
\r
79 ToolTipManager.sharedInstance().setDismissDelay(10000);
\r
80 PaintRefresher.Register(this, av.alignment);
\r
82 prefsize = getPreferredSize();
\r
83 orig = new float[npoint][3];
\r
85 for (int i = 0; i < npoint; i++)
\r
87 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
89 for (int j = 0; j < 3; j++)
\r
91 orig[i][j] = sp.coord[j];
\r
95 //Initialize the matrices to identity
\r
96 for (int i = 0; i < 3; i++)
\r
98 for (int j = 0; j < 3; j++)
\r
102 idmat.addElement(i, j, 0);
\r
103 objmat.addElement(i, j, 0);
\r
104 rotmat.addElement(i, j, 0);
\r
108 idmat.addElement(i, j, 0);
\r
109 objmat.addElement(i, j, 0);
\r
110 rotmat.addElement(i, j, 0);
\r
115 axes = new float[3][3];
\r
121 scale = findScale();
\r
123 // System.out.println("Scale factor = " + scale);
\r
124 addMouseListener(this);
\r
125 addKeyListener(this);
\r
127 // if (getParent() != null) {
\r
128 // getParent().addKeyListener(this);
\r
130 addMouseMotionListener(this);
\r
133 // rubberband = new RubberbandRectangle(this);
\r
134 // rubberband.setActive(true);
\r
135 // rubberband.addListener(this);
\r
138 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
139 redrawneeded = true;
\r
144 public void removeNotify() {
\r
145 controller.removeListener(this);
\r
146 super.removeNotify();
\r
148 public void initAxes()
\r
150 for (int i = 0; i < 3; i++)
\r
152 for (int j = 0; j < 3; j++)
\r
166 public void findWidth()
\r
168 max = new float[3];
\r
169 min = new float[3];
\r
171 max[0] = (float) - 1e30;
\r
172 max[1] = (float) - 1e30;
\r
173 max[2] = (float) - 1e30;
\r
175 min[0] = (float) 1e30;
\r
176 min[1] = (float) 1e30;
\r
177 min[2] = (float) 1e30;
\r
179 for (int i = 0; i < 3; i++)
\r
181 for (int j = 0; j < npoint; j++)
\r
183 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
185 if (sp.coord[i] >= max[i])
\r
187 max[i] = sp.coord[i];
\r
190 if (sp.coord[i] <= min[i])
\r
192 min[i] = sp.coord[i];
\r
197 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
198 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
199 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
200 width[0] = Math.abs(max[0] - min[0]);
\r
201 width[1] = Math.abs(max[1] - min[1]);
\r
202 width[2] = Math.abs(max[2] - min[2]);
\r
204 maxwidth = width[0];
\r
206 if (width[1] > width[0])
\r
208 maxwidth = width[1];
\r
211 if (width[2] > width[1])
\r
213 maxwidth = width[2];
\r
216 //System.out.println("Maxwidth = " + maxwidth);
\r
219 public float findScale()
\r
225 if (getWidth() != 0)
\r
227 width = getWidth();
\r
228 height = getHeight();
\r
232 width = prefsize.width;
\r
233 height = prefsize.height;
\r
236 if (width < height)
\r
245 return (float) ( (dim * scalefactor) / (2 * maxwidth));
\r
248 public void findCentre()
\r
250 //Find centre coordinate
\r
253 centre[0] = (max[0] + min[0]) / 2;
\r
254 centre[1] = (max[1] + min[1]) / 2;
\r
255 centre[2] = (max[2] + min[2]) / 2;
\r
257 // System.out.println("Centre x " + centre[0]);
\r
258 //System.out.println("Centre y " + centre[1]);
\r
259 //System.out.println("Centre z " + centre[2]);
\r
262 public Dimension getPreferredSize()
\r
264 if (prefsize != null)
\r
270 return new Dimension(400, 400);
\r
274 public Dimension getMinimumSize()
\r
276 return getPreferredSize();
\r
279 public void paintComponent(Graphics g)
\r
281 //Only create the image at the beginning -
\r
282 if ( (img == null) || (prefsize.width != getWidth()) ||
\r
283 (prefsize.height != getHeight()))
\r
285 prefsize.width = getWidth();
\r
286 prefsize.height = getHeight();
\r
288 scale = findScale();
\r
290 // System.out.println("New scale = " + scale);
\r
291 img = createImage(getWidth(), getHeight());
\r
292 ig = img.getGraphics();
\r
295 drawBackground(ig, Color.black);
\r
298 if (drawAxes == true)
\r
303 g.drawImage(img, 0, 0, this);
\r
306 public void drawAxes(Graphics g)
\r
308 g.setColor(Color.yellow);
\r
310 for (int i = 0; i < 3; i++)
\r
312 g.drawLine(getWidth() / 2, getHeight() / 2,
\r
313 (int) ( (axes[i][0] * scale * max[0]) + (getWidth() / 2)),
\r
314 (int) ( (axes[i][1] * scale * max[1]) + (getHeight() / 2)));
\r
318 public void drawBackground(Graphics g, Color col)
\r
321 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
324 public void drawScene(Graphics g)
\r
326 boolean darker = false;
\r
328 int halfwidth = getWidth() / 2;
\r
329 int halfheight = getHeight() / 2;
\r
331 for (int i = 0; i < npoint; i++)
\r
333 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
334 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) +
\r
336 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) +
\r
338 float z = sp.coord[1] - centre[2];
\r
340 if (sp.sequence.getColor() == Color.black)
\r
342 g.setColor(Color.white);
\r
346 g.setColor(sp.sequence.getColor());
\r
349 if (av.getSelectionGroup() != null)
\r
351 if (av.getSelectionGroup().sequences.contains(
\r
352 ( (SequencePoint) points.elementAt(i)).sequence))
\r
354 g.setColor(Color.gray);
\r
360 g.setColor(g.getColor().darker());
\r
363 g.fillRect(x - 3, y - 3, 6, 6);
\r
364 g.setColor(Color.red);
\r
367 // //Now the rectangle
\r
368 // if (rectx2 != -1 && recty2 != -1) {
\r
369 // g.setColor(Color.white);
\r
371 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
375 public Dimension minimumsize()
\r
380 public Dimension preferredsize()
\r
385 public void keyTyped(KeyEvent evt)
\r
389 public void keyReleased(KeyEvent evt)
\r
393 public void keyPressed(KeyEvent evt)
\r
397 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
399 scalefactor = (float) (scalefactor * 1.1);
\r
400 scale = findScale();
\r
402 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
404 scalefactor = (float) (scalefactor * 0.9);
\r
405 scale = findScale();
\r
407 else if (evt.getKeyChar() == 's')
\r
409 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
411 if ( (rectx2 != -1) && (recty2 != -1))
\r
413 rectSelect(rectx1, recty1, rectx2, recty2);
\r
420 public void printPoints()
\r
422 for (int i = 0; i < npoint; i++)
\r
424 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
425 Format.print(System.out, "%5d ", i);
\r
427 for (int j = 0; j < 3; j++)
\r
429 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
432 System.out.println();
\r
436 public void mouseClicked(MouseEvent evt)
\r
440 public void mouseEntered(MouseEvent evt)
\r
444 public void mouseExited(MouseEvent evt)
\r
448 public void mouseReleased(MouseEvent evt)
\r
452 public void mousePressed(MouseEvent evt)
\r
454 int x = evt.getX();
\r
455 int y = evt.getY();
\r
472 SequenceI found = findPoint(x, y);
\r
476 if (av.getSelectionGroup() != null)
\r
478 av.getSelectionGroup().addOrRemove(found, true);
\r
479 PaintRefresher.Refresh(this, av.alignment);
\r
483 av.setSelectionGroup(new SequenceGroup());
\r
484 av.getSelectionGroup().addOrRemove(found, true);
\r
485 av.getSelectionGroup().setEndRes(av.alignment.getWidth());
\r
492 // private void fireSequenceSelectionEvent(Selection sel) {
\r
493 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
495 public void mouseMoved(MouseEvent evt)
\r
497 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
501 this.setToolTipText(found.getName());
\r
505 this.setToolTipText(null);
\r
509 public void mouseDragged(MouseEvent evt)
\r
514 //Check if this is a rectangle drawing drag
\r
515 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
517 // rectx2 = evt.getX();
\r
518 // recty2 = evt.getY();
\r
522 rotmat.setIdentity();
\r
524 rotmat.rotate( (float) (my - omy), 'x');
\r
525 rotmat.rotate( (float) (mx - omx), 'y');
\r
527 for (int i = 0; i < npoint; i++)
\r
529 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
530 sp.coord[0] -= centre[0];
\r
531 sp.coord[1] -= centre[1];
\r
532 sp.coord[2] -= centre[2];
\r
534 //Now apply the rotation matrix
\r
535 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
537 //Now translate back again
\r
538 sp.coord[0] += centre[0];
\r
539 sp.coord[1] += centre[1];
\r
540 sp.coord[2] += centre[2];
\r
543 for (int i = 0; i < 3; i++)
\r
545 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
551 paint(this.getGraphics());
\r
555 public void rectSelect(int x1, int y1, int x2, int y2)
\r
557 boolean changedSel = false;
\r
559 for (int i = 0; i < npoint; i++)
\r
561 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
562 int tmp1 = (int) ( ( (sp.coord[0] - centre[0]) * scale) +
\r
563 ( (float) getWidth() / 2.0));
\r
564 int tmp2 = (int) ( ( (sp.coord[1] - centre[1]) * scale) +
\r
565 ( (float) getHeight() / 2.0));
\r
567 if ( (tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
\r
571 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
574 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
580 // if (changedSel) {
\r
581 // fireSequenceSelectionEvent(av.getSelection());
\r
585 public SequenceI findPoint(int x, int y)
\r
587 int halfwidth = getWidth() / 2;
\r
588 int halfheight = getHeight() / 2;
\r
592 for (int i = 0; i < npoint; i++)
\r
594 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
595 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) +
\r
597 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) +
\r
600 if ( (Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
\r
608 return ( (SequencePoint) points.elementAt(found)).sequence;
\r
616 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
617 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
620 Rubberband rb = (Rubberband)evt.getSource();
\r
622 // Clear the current selection (instance variable)
\r
623 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
624 // clearSelection();
\r
627 if (rb.getComponent() == this) {
\r
628 Rectangle bounds = evt.getBounds();
\r
629 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
632 redrawneeded = true;
\r
633 paint(this.getGraphics());
\r