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
21 import jalview.datamodel.*;
\r
24 import java.awt.image.*;
\r
26 import javax.swing.*;
\r
33 * @version $Revision$
\r
35 public class SeqCanvas extends JComponent
\r
38 SequenceRenderer sr;
\r
44 SearchResults searchResults = null;
\r
45 boolean fastPaint = false;
\r
50 * Creates a new SeqCanvas object.
\r
52 * @param av DOCUMENT ME!
\r
54 public SeqCanvas(AlignViewport av)
\r
57 fr = new FeatureRenderer(av);
\r
58 sr = new SequenceRenderer(av);
\r
59 setLayout(new BorderLayout());
\r
60 PaintRefresher.Register(this, av.alignment);
\r
61 setBackground(Color.white);
\r
64 MCview.PDBCanvas pdbCanvas;
\r
65 public SequenceRenderer getSequenceRenderer()
\r
70 public FeatureRenderer getFeatureRenderer()
\r
75 public void setPDBCanvas(MCview.PDBCanvas pc)
\r
80 public AlignViewport getViewport()
\r
89 * @param g DOCUMENT ME!
\r
90 * @param startx DOCUMENT ME!
\r
91 * @param endx DOCUMENT ME!
\r
92 * @param ypos DOCUMENT ME!
\r
94 void drawNorthScale(Graphics g, int startx, int endx, int ypos)
\r
96 int scalestartx = startx - (startx % 10) + 10;
\r
98 g.setColor(Color.black);
\r
101 for (int i = scalestartx; i < endx; i += 10)
\r
104 if(av.hasHiddenColumns)
\r
105 value = av.getColumnSelection().adjustForHiddenColumns(value);
\r
107 g.drawString( String.valueOf(value), (i - startx - 1) * av.charWidth,
\r
108 ypos - (av.charHeight / 2));
\r
110 g.drawLine(((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
\r
111 (ypos + 2) - (av.charHeight / 2),
\r
112 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -
\r
120 * @param g DOCUMENT ME!
\r
121 * @param startx DOCUMENT ME!
\r
122 * @param endx DOCUMENT ME!
\r
123 * @param ypos DOCUMENT ME!
\r
125 void drawWestScale(Graphics g, int startx, int endx, int ypos)
\r
127 FontMetrics fm = getFontMetrics(av.getFont());
\r
128 ypos += av.charHeight;
\r
130 if(av.hasHiddenColumns)
\r
131 startx = av.getColumnSelection().adjustForHiddenColumns(startx);
\r
134 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
136 SequenceI seq = av.alignment.getSequenceAt(i);
\r
137 int index = startx;
\r
140 while (index < endx)
\r
142 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
\r
149 value = av.alignment.getSequenceAt(i).findPosition(index);
\r
156 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))-av.charWidth/2;
\r
157 g.drawString(value + "", x,
\r
158 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
\r
166 * @param g DOCUMENT ME!
\r
167 * @param startx DOCUMENT ME!
\r
168 * @param endx DOCUMENT ME!
\r
169 * @param ypos DOCUMENT ME!
\r
171 void drawEastScale(Graphics g, int startx, int endx, int ypos)
\r
173 ypos += av.charHeight;
\r
175 if(av.hasHiddenColumns)
\r
176 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
\r
179 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
181 SequenceI seq = av.alignment.getSequenceAt(i);
\r
187 while (index > startx)
\r
189 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
\r
196 value = av.alignment.getSequenceAt(i).findPosition(index);
\r
203 g.drawString(String.valueOf(value), 0,
\r
204 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
\r
212 * @param horizontal DOCUMENT ME!
\r
213 * @param vertical DOCUMENT ME!
\r
215 public void fastPaint(int horizontal, int vertical)
\r
225 gg.copyArea(horizontal * av.charWidth,
\r
226 vertical * av.charHeight,
\r
229 -horizontal * av.charWidth,
\r
230 -vertical * av.charHeight);
\r
232 int sr = av.startRes;
\r
233 int er = av.endRes;
\r
234 int ss = av.startSeq;
\r
235 int es = av.endSeq;
\r
240 if (horizontal > 0) // scrollbar pulled right, image to the left
\r
243 transX = (er - sr - horizontal) * av.charWidth;
\r
244 sr = er - horizontal;
\r
246 else if (horizontal < 0)
\r
248 er = sr - horizontal-1;
\r
250 else if (vertical > 0) // scroll down
\r
252 ss = es - vertical;
\r
254 if (ss < av.startSeq)
\r
255 { // ie scrolling too fast, more than a page at a time
\r
260 transY = imgHeight - (vertical * av.charHeight);
\r
263 else if (vertical < 0)
\r
265 es = ss - vertical;
\r
267 if (es > av.endSeq)
\r
273 gg.translate(transX, transY);
\r
274 drawPanel(gg, sr, er, ss, es, 0);
\r
275 gg.translate(-transX, -transY);
\r
281 * Definitions of startx and endx (hopefully):
\r
282 * SMJS This is what I'm working towards!
\r
283 * startx is the first residue (starting at 0) to display.
\r
284 * endx is the last residue to display (starting at 0).
\r
285 * starty is the first sequence to display (starting at 0).
\r
286 * endy is the last sequence to display (starting at 0).
\r
287 * NOTE 1: The av limits are set in setFont in this class and
\r
288 * in the adjustment listener in SeqPanel when the scrollbars move.
\r
291 // Set this to false to force a full panel paint
\r
292 public void paintComponent(Graphics g)
\r
294 super.paintComponent(g);
\r
298 if ( img != null && (fastPaint
\r
299 || (getVisibleRect().width != g.getClipBounds().width)
\r
300 || (getVisibleRect().height != g.getClipBounds().height)))
\r
302 g.drawImage(img, 0, 0, this);
\r
308 // this draws the whole of the alignment
\r
309 imgWidth = getWidth();
\r
310 imgHeight = getHeight();
\r
312 imgWidth -= (imgWidth % av.charWidth);
\r
313 imgHeight -= (imgHeight % av.charHeight);
\r
315 if ((imgWidth < 1) || (imgHeight < 1))
\r
320 img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
\r
321 gg = (Graphics2D) img.getGraphics();
\r
322 gg.setFont(av.getFont());
\r
325 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
\r
326 RenderingHints.VALUE_ANTIALIAS_ON);
\r
328 gg.setColor(Color.white);
\r
329 gg.fillRect(0, 0, imgWidth, imgHeight);
\r
332 if (av.getWrapAlignment())
\r
334 drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);
\r
338 drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
\r
341 g.drawImage(img, 0, 0, this);
\r
343 if (pdbCanvas != null)
\r
345 pdbCanvas.updateSeqColours();
\r
353 * @param cwidth DOCUMENT ME!
\r
355 * @return DOCUMENT ME!
\r
357 public int getWrappedCanvasWidth(int cwidth)
\r
359 FontMetrics fm = getFontMetrics(av.getFont());
\r
364 if (av.scaleRightWrapped)
\r
366 LABEL_EAST = fm.stringWidth(getMask());
\r
369 if (av.scaleLeftWrapped)
\r
371 LABEL_WEST = fm.stringWidth(getMask());
\r
374 return (cwidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
\r
379 * Generates a string of zeroes.
\r
384 String mask = "00";
\r
385 for (int i = av.alignment.getWidth(); i > 0; i /= 10)
\r
395 * @param g DOCUMENT ME!
\r
396 * @param canvasWidth DOCUMENT ME!
\r
397 * @param canvasHeight DOCUMENT ME!
\r
398 * @param startRes DOCUMENT ME!
\r
400 public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,
\r
404 AlignmentI al = av.getAlignment();
\r
406 FontMetrics fm = getFontMetrics(av.getFont());
\r
408 int LABEL_EAST = 0;
\r
410 if (av.scaleRightWrapped)
\r
412 LABEL_EAST = fm.stringWidth(getMask());
\r
415 int LABEL_WEST = 0;
\r
417 if (av.scaleLeftWrapped)
\r
419 LABEL_WEST = fm.stringWidth(getMask());
\r
422 int hgap = av.charHeight;
\r
423 if(av.scaleAboveWrapped)
\r
424 hgap += av.charHeight;
\r
426 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
\r
427 int cHeight = av.getAlignment().getHeight() * av.charHeight;
\r
429 av.setWrappedWidth(cWidth);
\r
431 av.endRes = av.startRes + cWidth;
\r
434 int endx = (startRes + cWidth) - 1;
\r
437 while ((ypos <= canvasHeight) && (startRes < av.alignment.getWidth()))
\r
439 g.setFont(av.getFont());
\r
440 g.setColor(Color.black);
\r
442 if (av.scaleLeftWrapped)
\r
444 drawWestScale(g, startRes, endx, ypos);
\r
447 if (av.scaleRightWrapped)
\r
449 g.translate(canvasWidth - LABEL_EAST, 0);
\r
450 drawEastScale(g, startRes, endx, ypos);
\r
451 g.translate(-(canvasWidth - LABEL_EAST), 0);
\r
454 g.translate(LABEL_WEST, 0);
\r
456 if (av.scaleAboveWrapped)
\r
458 drawNorthScale(g, startRes, endx, ypos);
\r
461 // When printing we have an extra clipped region,
\r
462 // the Printable page which we need to account for here
\r
463 Shape clip = g.getClip();
\r
467 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);
\r
471 g.setClip(0, (int) clip.getBounds().getY(),
\r
472 cWidth * av.charWidth, (int) clip.getBounds().getHeight());
\r
475 if (av.vconsensus!=null && av.alignment.getWidth() >= av.vconsensus.size())
\r
477 endx = av.vconsensus.size() - 2;
\r
481 drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
\r
483 if(av.showAnnotation)
\r
485 g.translate(0, cHeight + ypos + 3);
\r
486 if(annotations==null)
\r
487 annotations = new AnnotationPanel(av);
\r
489 annotations.drawComponent( (Graphics2D) g, startRes, endx + 1);
\r
490 g.translate(0, -cHeight - ypos);
\r
493 g.translate(-LABEL_WEST, 0);
\r
495 ypos += cHeight+getAnnotationHeight()+hgap;
\r
496 if(av.showAnnotation)
\r
499 startRes += cWidth;
\r
500 endx = (startRes + cWidth) - 1;
\r
502 if (endx > al.getWidth())
\r
504 endx = al.getWidth();
\r
509 AnnotationPanel annotations;
\r
510 int getAnnotationHeight()
\r
512 if(!av.showAnnotation)
\r
515 if(annotations==null)
\r
516 annotations = new AnnotationPanel(av);
\r
518 return annotations.adjustPanelHeight();
\r
524 * @param g1 DOCUMENT ME!
\r
525 * @param x1 DOCUMENT ME!
\r
526 * @param x2 DOCUMENT ME!
\r
527 * @param y1 DOCUMENT ME!
\r
528 * @param y2 DOCUMENT ME!
\r
529 * @param startx DOCUMENT ME!
\r
530 * @param starty DOCUMENT ME!
\r
531 * @param offset DOCUMENT ME!
\r
534 float aaRatio = 2f/3f;
\r
535 public void increaseAARatio()
\r
544 public void decreaseAARation()
\r
554 void drawPanel(Graphics g1, int startRes, int endRes,
\r
555 int startSeq, int endSeq, int offset)
\r
557 if(!av.hasHiddenColumns)
\r
559 draw(g1, startRes, endRes, startSeq, endSeq, offset);
\r
563 java.util.Vector regions = av.getColumnSelection().getHiddenColumns();
\r
566 int blockStart = startRes;
\r
567 int blockEnd = endRes;
\r
569 for (int i = 0; i < regions.size(); i++)
\r
571 int[] region = (int[]) regions.elementAt(i);
\r
572 int hideStart = region[0];
\r
573 int hideEnd = region[1];
\r
575 if (hideStart <= blockStart)
\r
577 blockStart += (hideEnd - hideStart) + 1;
\r
581 blockEnd = hideStart - 1;
\r
583 g1.translate(screenY * av.charWidth, 0);
\r
585 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
587 g1.setColor(Color.blue);
\r
588 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
590 (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
591 startSeq + (endSeq - startSeq) * av.charHeight + offset);
\r
592 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth,
\r
594 (blockEnd - blockStart + 1) * av.charWidth,
\r
595 startSeq + (endSeq - startSeq) * av.charHeight + offset);
\r
597 g1.translate( -screenY * av.charWidth, 0);
\r
598 screenY += blockEnd - blockStart + 1;
\r
599 blockStart = hideEnd + 1;
\r
602 if (screenY <= (endRes - startRes))
\r
604 blockEnd = blockStart + (endRes - startRes) - screenY;
\r
605 g1.translate(screenY * av.charWidth, 0);
\r
606 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
607 g1.translate( -screenY * av.charWidth, 0);
\r
616 //int startRes, int endRes, int startSeq, int endSeq, int x, int y,
\r
617 // int x1, int x2, int y1, int y2, int startx, int starty,
\r
618 void draw(Graphics g1,
\r
619 int startRes, int endRes,
\r
620 int startSeq, int endSeq,
\r
624 sr.renderGaps(av.renderGaps);
\r
625 Graphics2D g = (Graphics2D) g1;
\r
626 g.setFont(av.getFont());
\r
630 /// First draw the sequences
\r
631 /////////////////////////////
\r
632 for (int i = startSeq; i < endSeq; i++)
\r
634 nextSeq = av.alignment.getSequenceAt(i);
\r
636 sr.drawSequence(g, nextSeq, av.alignment.findAllGroups(nextSeq),
\r
638 offset + ( (i - startSeq) * av.charHeight));
\r
640 if (av.showSequenceFeatures)
\r
642 fr.drawSequence(g1, nextSeq, startRes, endRes,
\r
643 offset + ((i - startSeq) * av.charHeight), av.charWidth,
\r
647 /// Highlight search Results once all sequences have been drawn
\r
648 //////////////////////////////////////////////////////////
\r
649 if (searchResults != null)
\r
651 int[] visibleResults = searchResults.getResults(nextSeq, startRes, endRes);
\r
652 if (visibleResults != null)
\r
653 for (int r = 0; r < visibleResults.length; r += 2)
\r
655 sr.drawHighlightedText(nextSeq, visibleResults[r],
\r
656 visibleResults[r + 1],
\r
657 (visibleResults[r] - startRes) * av.charWidth,
\r
658 offset + ( (i - startSeq) * av.charHeight),
\r
659 av.charWidth, av.charHeight);
\r
665 /////////////////////////////////////
\r
666 // Now outline any areas if necessary
\r
667 /////////////////////////////////////
\r
668 SequenceGroup group = av.getSelectionGroup();
\r
673 int groupIndex = -1;
\r
675 if ((group == null) && (av.alignment.getGroups().size() > 0))
\r
677 group = (SequenceGroup) av.alignment.getGroups().elementAt(0);
\r
687 boolean inGroup = false;
\r
691 for (i = startSeq; i < endSeq; i++)
\r
693 sx = (group.getStartRes() - startRes) * av.charWidth;
\r
694 sy = offset + ((i - startSeq) * av.charHeight);
\r
695 ex = (((group.getEndRes() + 1) - group.getStartRes()) * av.charWidth) -
\r
698 if(sx+ex<0 || sx>imgWidth)
\r
703 if ( (sx <= (endRes-startRes)*av.charWidth) &&
\r
704 group.sequences.contains(av.alignment.getSequenceAt(
\r
707 if ((bottom == -1) &&
\r
708 !group.sequences.contains(
\r
709 av.alignment.getSequenceAt(i + 1)))
\r
711 bottom = sy + av.charHeight;
\r
716 if (((top == -1) && (i == 0)) ||
\r
717 !group.sequences.contains(
\r
718 av.alignment.getSequenceAt(i - 1)))
\r
726 if (group == av.getSelectionGroup())
\r
728 g.setStroke(new BasicStroke(1,
\r
729 BasicStroke.CAP_BUTT,
\r
730 BasicStroke.JOIN_ROUND, 3f,
\r
731 new float[] { 5f, 3f }, 0f));
\r
732 g.setColor(Color.RED);
\r
736 g.setStroke(new BasicStroke());
\r
737 g.setColor(group.getOutlineColour());
\r
745 if (sx >= 0 && sx < imgWidth)
\r
746 g.drawLine(sx, oldY, sx, sy);
\r
748 if (sx + ex < imgWidth)
\r
749 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
757 if (sx + ex > imgWidth)
\r
760 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
761 ex = (endRes - startRes + 1) * av.charWidth;
\r
765 g.drawLine(sx, top, sx + ex, top);
\r
771 g.drawLine(sx, bottom, sx + ex, bottom);
\r
782 sy = offset + ( (i - startSeq) * av.charHeight);
\r
783 if (sx >= 0 && sx < imgWidth)
\r
784 g.drawLine(sx, oldY, sx, sy);
\r
786 if (sx + ex < imgWidth)
\r
787 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
795 if (sx + ex > imgWidth)
\r
797 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
798 ex = (endRes - startRes + 1) * av.charWidth;
\r
802 g.drawLine(sx, top, sx + ex, top);
\r
808 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
\r
817 if (groupIndex >= av.alignment.getGroups().size())
\r
822 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);
\r
824 while (groupIndex < av.alignment.getGroups().size());
\r
831 * @param results DOCUMENT ME!
\r
833 public void highlightSearchResults(SearchResults results)
\r
837 searchResults = results;
\r