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
20 package jalview.gui;
\r
22 import jalview.math.*;
\r
23 import jalview.datamodel.*;
\r
24 import jalview.util.*;
\r
27 import java.awt.event.*;
\r
28 import javax.swing.*;
\r
32 public class RotatableCanvas extends JPanel implements MouseListener,
\r
33 MouseMotionListener,
\r
35 //RubberbandListener,
\r
36 //SequenceSelectionListener
\r
38 RotatableMatrix idmat = new RotatableMatrix(3,3);
\r
39 RotatableMatrix objmat = new RotatableMatrix(3,3);
\r
40 RotatableMatrix rotmat = new RotatableMatrix(3,3);
\r
42 //RubberbandRectangle rubberband;
\r
44 boolean drawAxes = true;
\r
56 float centre[] = new float[3];
\r
57 float width[] = new float[3];
\r
59 float max[] = new float[3];
\r
60 float min[] = new float[3];
\r
82 float scalefactor = 1;
\r
85 // Controller controller;
\r
88 public RotatableCanvas(AlignViewport av,
\r
89 Vector points, int npoint) {
\r
90 this.points = points;
\r
91 this.npoint = npoint;
\r
93 ToolTipManager.sharedInstance().registerComponent(this);
\r
94 PaintRefresher.Register(this);
\r
96 prefsize = getPreferredSize();
\r
97 orig = new float[npoint][3];
\r
99 for (int i=0; i < npoint; i++) {
\r
100 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
101 for (int j=0; j < 3; j++) {
\r
102 orig[i][j] = sp.coord[j];
\r
105 //Initialize the matrices to identity
\r
107 for (int i = 0; i < 3; i++) {
\r
108 for (int j = 0; j < 3 ; j++) {
\r
110 idmat.addElement(i,j,0);
\r
111 objmat.addElement(i,j,0);
\r
112 rotmat.addElement(i,j,0);
\r
114 idmat.addElement(i,j,0);
\r
115 objmat.addElement(i,j,0);
\r
116 rotmat.addElement(i,j,0);
\r
121 axes = new float[3][3];
\r
127 scale = findScale();
\r
129 // System.out.println("Scale factor = " + scale);
\r
131 addMouseListener(this);
\r
132 addKeyListener(this);
\r
133 // if (getParent() != null) {
\r
134 // getParent().addKeyListener(this);
\r
136 addMouseMotionListener(this);
\r
139 // rubberband = new RubberbandRectangle(this);
\r
140 // rubberband.setActive(true);
\r
141 // rubberband.addListener(this);
\r
144 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
145 redrawneeded = true;
\r
150 public void removeNotify() {
\r
151 controller.removeListener(this);
\r
152 super.removeNotify();
\r
155 public void initAxes() {
\r
156 for (int i = 0; i < 3; i++) {
\r
157 for (int j=0; j < 3; j++) {
\r
167 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
180 for (int j = 0; j < npoint; j++) {
\r
181 SequencePoint sp = (SequencePoint)points.elementAt(j);
\r
182 if (sp.coord[i] >= max[i]) {
\r
183 max[i] = sp.coord[i];
\r
185 if (sp.coord[i] <= min[i]) {
\r
186 min[i] = sp.coord[i];
\r
191 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
192 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
193 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
195 width[0] = Math.abs(max[0] - min[0]);
\r
196 width[1] = Math.abs(max[1] - min[1]);
\r
197 width[2] = Math.abs(max[2] - min[2]);
\r
199 maxwidth = width[0];
\r
201 if (width[1] > width[0])
\r
202 maxwidth = width[1];
\r
203 if (width[2] > width[1])
\r
204 maxwidth = width[2];
\r
206 //System.out.println("Maxwidth = " + maxwidth);
\r
209 public float findScale() {
\r
210 int dim, width, height;
\r
211 if (getWidth() != 0) {
\r
212 width = getWidth();
\r
213 height = getHeight();
\r
215 width = prefsize.width;
\r
216 height = prefsize.height;
\r
219 if (width < height) {
\r
225 return (float)(dim*scalefactor/(2*maxwidth));
\r
228 public void findCentre() {
\r
229 //Find centre coordinate
\r
232 centre[0] = (max[0] + min[0])/2;
\r
233 centre[1] = (max[1] + min[1])/2;
\r
234 centre[2] = (max[2] + min[2])/2;
\r
236 // System.out.println("Centre x " + centre[0]);
\r
237 //System.out.println("Centre y " + centre[1]);
\r
238 //System.out.println("Centre z " + centre[2]);
\r
241 public Dimension getPreferredSize() {
\r
242 if (prefsize != null) {
\r
245 return new Dimension(400,400);
\r
249 public Dimension getMinimumSize() {
\r
250 return getPreferredSize();
\r
253 public void paintComponent(Graphics g) {
\r
254 //Only create the image at the beginning -
\r
255 if ((img == null) || (prefsize.width != getWidth()) || (prefsize.height != getHeight())) {
\r
256 prefsize.width = getWidth();
\r
257 prefsize.height = getHeight();
\r
259 scale = findScale();
\r
261 // System.out.println("New scale = " + scale);
\r
262 img = createImage(getWidth(),getHeight());
\r
263 ig = img.getGraphics();
\r
268 drawBackground(ig,Color.black);
\r
270 if (drawAxes == true)
\r
276 g.drawImage(img,0,0,this);
\r
279 public void drawAxes(Graphics g) {
\r
281 g.setColor(Color.yellow);
\r
282 for (int i=0; i < 3 ; i++) {
\r
283 g.drawLine(getWidth()/2,getHeight()/2,
\r
284 (int)(axes[i][0]*scale*max[0] + getWidth()/2),
\r
285 (int)(axes[i][1]*scale*max[1] + getHeight()/2));
\r
289 public void drawBackground(Graphics g, Color col) {
\r
291 g.fillRect(0,0,prefsize.width,prefsize.height);
\r
295 public void drawScene(Graphics g) {
\r
296 boolean darker = false;
\r
298 int halfwidth = getWidth()/2;
\r
299 int halfheight = getHeight()/2;
\r
301 for (int i = 0; i < npoint; i++) {
\r
302 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
303 int x = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;
\r
304 int y = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;
\r
305 float z = sp.coord[1] - centre[2];
\r
310 if (sp.sequence.getColor() == Color.black)
\r
311 g.setColor(Color.white);
\r
313 g.setColor(sp.sequence.getColor());
\r
316 if (av.getSelectionGroup() != null)
\r
318 if (av.getSelectionGroup().sequences.contains(((SequencePoint)points.elementAt(i)).sequence))
\r
319 g.setColor(Color.gray);
\r
322 g.setColor(g.getColor().darker());
\r
325 g.fillRect(x-3,y-3,6,6);
\r
326 g.setColor(Color.red);
\r
328 // //Now the rectangle
\r
329 // if (rectx2 != -1 && recty2 != -1) {
\r
330 // g.setColor(Color.white);
\r
332 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
336 public Dimension minimumsize() {
\r
340 public Dimension preferredsize() {
\r
344 public void keyTyped(KeyEvent evt) { }
\r
345 public void keyReleased(KeyEvent evt) { }
\r
347 public void keyPressed(KeyEvent evt) {
\r
349 if (evt.getKeyCode() == KeyEvent.VK_UP) {
\r
350 scalefactor = (float)(scalefactor * 1.1);
\r
351 scale = findScale();
\r
352 } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) {
\r
353 scalefactor = (float)(scalefactor * 0.9);
\r
354 scale = findScale();
\r
355 } else if (evt.getKeyChar() == 's') {
\r
356 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
357 if (rectx2 != -1 && recty2 != -1) {
\r
358 rectSelect(rectx1,recty1,rectx2,recty2);
\r
365 public void printPoints() {
\r
366 for (int i=0; i < npoint; i++) {
\r
367 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
368 Format.print(System.out,"%5d ", i);
\r
369 for (int j=0; j < 3;j++) {
\r
370 Format.print(System.out,"%13.3f ",sp.coord[j]);
\r
372 System.out.println();
\r
376 public void mouseClicked(MouseEvent evt) { }
\r
377 public void mouseEntered(MouseEvent evt) { }
\r
378 public void mouseExited(MouseEvent evt) { }
\r
379 public void mouseReleased(MouseEvent evt) { }
\r
381 public void mousePressed(MouseEvent evt) {
\r
382 int x = evt.getX();
\r
383 int y = evt.getY();
\r
400 SequenceI found = findPoint(x,y);
\r
404 if (av.getSelectionGroup() != null)
\r
406 av.getSelectionGroup().addOrRemove(found);
\r
407 PaintRefresher.Refresh(this);
\r
411 av.setSelectionGroup(new SequenceGroup());
\r
412 av.getSelectionGroup().addOrRemove(found);
\r
413 av.getSelectionGroup().setEndRes(av.alignment.getWidth());
\r
420 // private void fireSequenceSelectionEvent(Selection sel) {
\r
421 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
424 public void mouseMoved(MouseEvent evt)
\r
426 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
428 this.setToolTipText(found.getName());
\r
430 this.setToolTipText(null);
\r
433 public void mouseDragged(MouseEvent evt) {
\r
436 //Check if this is a rectangle drawing drag
\r
437 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {
\r
438 // rectx2 = evt.getX();
\r
439 // recty2 = evt.getY();
\r
441 rotmat.setIdentity();
\r
443 rotmat.rotate((float)(my-omy),'x');
\r
444 rotmat.rotate((float)(mx-omx),'y');
\r
446 for (int i = 0; i < npoint; i++) {
\r
447 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
448 sp.coord[0] -= centre[0];
\r
449 sp.coord[1] -= centre[1];
\r
450 sp.coord[2] -= centre[2];
\r
452 //Now apply the rotation matrix
\r
453 sp.coord= rotmat.vectorMultiply(sp.coord);
\r
455 //Now translate back again
\r
456 sp.coord[0] += centre[0];
\r
457 sp.coord[1] += centre[1];
\r
458 sp.coord[2] += centre[2];
\r
461 for (int i=0; i < 3; i++) {
\r
462 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
467 paint(this.getGraphics());
\r
472 public void rectSelect(int x1, int y1, int x2, int y2) {
\r
473 boolean changedSel = false;
\r
474 for (int i=0; i < npoint; i++) {
\r
475 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
476 int tmp1 = (int)((sp.coord[0] - centre[0])*scale + (float)getWidth()/2.0);
\r
477 int tmp2 = (int)((sp.coord[1] - centre[1])*scale + (float)getHeight()/2.0);
\r
479 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2) {
\r
481 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
484 av.getSelectionGroup().addSequence(sp.sequence);
\r
489 // if (changedSel) {
\r
490 // fireSequenceSelectionEvent(av.getSelection());
\r
493 public SequenceI findPoint(int x, int y) {
\r
495 int halfwidth = getWidth()/2;
\r
496 int halfheight = getHeight()/2;
\r
500 for (int i=0; i < npoint; i++) {
\r
502 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
503 int px = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;
\r
504 int py = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;
\r
507 if (Math.abs(px-x)<3 && Math.abs(py - y) < 3 ) {
\r
512 return ((SequencePoint)points.elementAt(found)).sequence;
\r
517 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
518 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
521 Rubberband rb = (Rubberband)evt.getSource();
\r
523 // Clear the current selection (instance variable)
\r
524 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
525 // clearSelection();
\r
528 if (rb.getComponent() == this) {
\r
529 Rectangle bounds = evt.getBounds();
\r
530 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
533 redrawneeded = true;
\r
534 paint(this.getGraphics());
\r