2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 import jalview.datamodel.*;
24 import java.awt.image.*;
35 public class SeqCanvas extends JComponent
37 final FeatureRenderer fr;
38 final SequenceRenderer sr;
44 SearchResults searchResults = null;
45 boolean fastPaint = false;
55 * Creates a new SeqCanvas object.
57 * @param av DOCUMENT ME!
59 public SeqCanvas(AlignViewport av)
62 fr = new FeatureRenderer(av);
63 sr = new SequenceRenderer(av);
64 setLayout(new BorderLayout());
65 PaintRefresher.Register(this, av.alignment);
66 setBackground(Color.white);
69 MCview.PDBCanvas pdbCanvas;
70 public SequenceRenderer getSequenceRenderer()
75 public FeatureRenderer getFeatureRenderer()
80 public void setPDBCanvas(MCview.PDBCanvas pc)
85 public AlignViewport getViewport()
94 * @param g DOCUMENT ME!
95 * @param startx DOCUMENT ME!
96 * @param endx DOCUMENT ME!
97 * @param ypos DOCUMENT ME!
99 void drawNorthScale(Graphics g, int startx, int endx, int ypos)
101 int scalestartx = startx - (startx % 10) + 10;
103 g.setColor(Color.black);
106 for (int i = scalestartx; i < endx; i += 10)
109 if(av.hasHiddenColumns)
110 value = av.getColumnSelection().adjustForHiddenColumns(value);
112 g.drawString( String.valueOf(value), (i - startx - 1) * av.charWidth,
113 ypos - (av.charHeight / 2));
115 g.drawLine(((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
116 (ypos + 2) - (av.charHeight / 2),
117 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -
125 * @param g DOCUMENT ME!
126 * @param startx DOCUMENT ME!
127 * @param endx DOCUMENT ME!
128 * @param ypos DOCUMENT ME!
130 void drawWestScale(Graphics g, int startx, int endx, int ypos)
132 FontMetrics fm = getFontMetrics(av.getFont());
133 ypos += av.charHeight;
135 if(av.hasHiddenColumns)
137 startx = av.getColumnSelection().adjustForHiddenColumns(startx);
138 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
141 int maxwidth = av.alignment.getWidth();
142 if (av.hasHiddenColumns)
143 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
146 for (int i = 0; i < av.alignment.getHeight(); i++)
148 SequenceI seq = av.alignment.getSequenceAt(i);
154 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
161 value = av.alignment.getSequenceAt(i).findPosition(index);
168 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))-av.charWidth/2;
169 g.drawString(value + "", x,
170 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
178 * @param g DOCUMENT ME!
179 * @param startx DOCUMENT ME!
180 * @param endx DOCUMENT ME!
181 * @param ypos DOCUMENT ME!
183 void drawEastScale(Graphics g, int startx, int endx, int ypos)
185 ypos += av.charHeight;
187 if(av.hasHiddenColumns)
188 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
192 for (int i = 0; i < av.alignment.getHeight(); i++)
194 seq = av.alignment.getSequenceAt(i);
198 while (index > startx)
200 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
207 value = seq.findPosition(index);
214 g.drawString(String.valueOf(value), 0,
215 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
223 * @param horizontal DOCUMENT ME!
224 * @param vertical DOCUMENT ME!
226 public void fastPaint(int horizontal, int vertical)
236 gg.copyArea(horizontal * av.charWidth,
237 vertical * av.charHeight,
240 -horizontal * av.charWidth,
241 -vertical * av.charHeight);
243 int sr = av.startRes;
245 int ss = av.startSeq;
251 if (horizontal > 0) // scrollbar pulled right, image to the left
254 transX = (er - sr - horizontal) * av.charWidth;
255 sr = er - horizontal;
257 else if (horizontal < 0)
259 er = sr - horizontal-1;
261 else if (vertical > 0) // scroll down
265 if (ss < av.startSeq)
266 { // ie scrolling too fast, more than a page at a time
271 transY = imgHeight - (vertical * av.charHeight);
274 else if (vertical < 0)
284 gg.translate(transX, transY);
285 drawPanel(gg, sr, er, ss, es, 0);
286 gg.translate(-transX, -transY);
292 * Definitions of startx and endx (hopefully):
293 * SMJS This is what I'm working towards!
294 * startx is the first residue (starting at 0) to display.
295 * endx is the last residue to display (starting at 0).
296 * starty is the first sequence to display (starting at 0).
297 * endy is the last sequence to display (starting at 0).
298 * NOTE 1: The av limits are set in setFont in this class and
299 * in the adjustment listener in SeqPanel when the scrollbars move.
302 // Set this to false to force a full panel paint
303 public void paintComponent(Graphics g)
305 super.paintComponent(g);
309 if ( img != null && (fastPaint
310 || (getVisibleRect().width != g.getClipBounds().width)
311 || (getVisibleRect().height != g.getClipBounds().height)))
313 g.drawImage(img, 0, 0, this);
319 // this draws the whole of the alignment
320 imgWidth = getWidth();
321 imgHeight = getHeight();
323 imgWidth -= (imgWidth % av.charWidth);
324 imgHeight -= (imgHeight % av.charHeight);
326 if ((imgWidth < 1) || (imgHeight < 1))
331 img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
332 gg = (Graphics2D) img.getGraphics();
333 gg.setFont(av.getFont());
336 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
337 RenderingHints.VALUE_ANTIALIAS_ON);
339 gg.setColor(Color.white);
340 gg.fillRect(0, 0, imgWidth, imgHeight);
343 if (av.getWrapAlignment())
345 drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);
349 drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
352 g.drawImage(img, 0, 0, this);
354 if (pdbCanvas != null)
356 pdbCanvas.updateSeqColours();
364 * @param cwidth DOCUMENT ME!
366 * @return DOCUMENT ME!
368 public int getWrappedCanvasWidth(int cwidth)
370 FontMetrics fm = getFontMetrics(av.getFont());
375 if (av.scaleRightWrapped)
377 LABEL_EAST = fm.stringWidth(getMask());
380 if (av.scaleLeftWrapped)
382 LABEL_WEST = fm.stringWidth(getMask());
385 return (cwidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
390 * Generates a string of zeroes.
396 for (int i = av.alignment.getWidth(); i > 0; i /= 10)
406 * @param g DOCUMENT ME!
407 * @param canvasWidth DOCUMENT ME!
408 * @param canvasHeight DOCUMENT ME!
409 * @param startRes DOCUMENT ME!
411 public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,
414 AlignmentI al = av.getAlignment();
416 FontMetrics fm = getFontMetrics(av.getFont());
419 if (av.scaleRightWrapped)
421 LABEL_EAST = fm.stringWidth(getMask());
425 if (av.scaleLeftWrapped)
427 LABEL_WEST = fm.stringWidth(getMask());
430 int hgap = av.charHeight;
431 if(av.scaleAboveWrapped)
432 hgap += av.charHeight;
434 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
435 int cHeight = av.getAlignment().getHeight() * av.charHeight;
437 av.setWrappedWidth(cWidth);
439 av.endRes = av.startRes + cWidth;
444 int maxwidth = av.alignment.getWidth();
446 if(av.hasHiddenColumns)
447 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth)-1;
449 while ((ypos <= canvasHeight) && (startRes < maxwidth))
451 endx = startRes + cWidth -1;
458 g.setFont(av.getFont());
459 g.setColor(Color.black);
461 if (av.scaleLeftWrapped)
463 drawWestScale(g, startRes, endx, ypos);
466 if (av.scaleRightWrapped)
468 g.translate(canvasWidth - LABEL_EAST, 0);
469 drawEastScale(g, startRes, endx, ypos);
470 g.translate(-(canvasWidth - LABEL_EAST), 0);
473 g.translate(LABEL_WEST, 0);
475 if (av.scaleAboveWrapped)
477 drawNorthScale(g, startRes, endx, ypos);
480 if (av.hasHiddenColumns && av.showHiddenMarkers)
482 g.setColor(Color.blue);
484 for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size();
487 res = av.getColumnSelection().findHiddenRegionPosition(i) -
490 if (res < 0 || res > endx - startRes)
493 gg.fillPolygon(new int[]
494 {res * av.charWidth - av.charHeight / 4,
495 res * av.charWidth + av.charHeight / 4,
499 ypos - (av.charHeight / 2),
500 ypos - (av.charHeight / 2),
501 ypos - (av.charHeight / 2) + 8
509 // When printing we have an extra clipped region,
510 // the Printable page which we need to account for here
511 Shape clip = g.getClip();
515 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);
519 g.setClip(0, (int) clip.getBounds().getY(),
520 cWidth * av.charWidth, (int) clip.getBounds().getHeight());
523 drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
525 if(av.showAnnotation)
527 g.translate(0, cHeight + ypos + 3);
528 if(annotations==null)
529 annotations = new AnnotationPanel(av);
531 annotations.drawComponent( (Graphics2D) g, startRes, endx+1);
532 g.translate(0, -cHeight - ypos);
535 g.translate(-LABEL_WEST, 0);
537 ypos += cHeight+getAnnotationHeight()+hgap;
538 if(av.showAnnotation)
545 AnnotationPanel annotations;
546 int getAnnotationHeight()
548 if(!av.showAnnotation)
551 if(annotations==null)
552 annotations = new AnnotationPanel(av);
554 return annotations.adjustPanelHeight();
560 * @param g1 DOCUMENT ME!
561 * @param startRes DOCUMENT ME!
562 * @param endRes DOCUMENT ME!
563 * @param startSeq DOCUMENT ME!
564 * @param endSeq DOCUMENT ME!
565 * @param offset DOCUMENT ME!
567 void drawPanel(Graphics g1, int startRes, int endRes,
568 int startSeq, int endSeq, int offset)
570 if(!av.hasHiddenColumns)
572 draw(g1, startRes, endRes, startSeq, endSeq, offset);
576 java.util.Vector regions = av.getColumnSelection().getHiddenColumns();
579 int blockStart = startRes;
580 int blockEnd = endRes;
582 for (int i = 0; i < regions.size(); i++)
584 int[] region = (int[]) regions.elementAt(i);
585 int hideStart = region[0];
586 int hideEnd = region[1];
588 if (hideStart <= blockStart)
590 blockStart += (hideEnd - hideStart) + 1;
594 blockEnd = hideStart - 1;
596 g1.translate(screenY * av.charWidth, 0);
598 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
600 if(av.getShowHiddenMarkers())
602 g1.setColor(Color.blue);
603 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,
605 (blockEnd - blockStart + 1) * av.charWidth - 1,
606 startSeq + (endSeq - startSeq) * av.charHeight + offset);
609 g1.translate( -screenY * av.charWidth, 0);
610 screenY += blockEnd - blockStart + 1;
611 blockStart = hideEnd + 1;
614 if (screenY <= (endRes - startRes))
616 blockEnd = blockStart + (endRes - startRes) - screenY;
617 g1.translate(screenY * av.charWidth, 0);
618 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
620 g1.translate( -screenY * av.charWidth, 0);
629 //int startRes, int endRes, int startSeq, int endSeq, int x, int y,
630 // int x1, int x2, int y1, int y2, int startx, int starty,
631 void draw(Graphics g,
632 int startRes, int endRes,
633 int startSeq, int endSeq,
636 g.setFont(av.getFont());
637 sr.prepare(g, av.renderGaps);
641 /// First draw the sequences
642 /////////////////////////////
643 for (int i = startSeq; i < endSeq; i++)
645 nextSeq = av.alignment.getSequenceAt(i);
647 sr.drawSequence(nextSeq, av.alignment.findAllGroups(nextSeq),
649 offset + ( (i - startSeq) * av.charHeight));
651 if (av.showSequenceFeatures)
653 fr.drawSequence(g, nextSeq, startRes, endRes,
654 offset + ((i - startSeq) * av.charHeight));
657 /// Highlight search Results once all sequences have been drawn
658 //////////////////////////////////////////////////////////
659 if (searchResults != null)
661 int[] visibleResults = searchResults.getResults(nextSeq, startRes, endRes);
662 if (visibleResults != null)
663 for (int r = 0; r < visibleResults.length; r += 2)
665 sr.drawHighlightedText(nextSeq, visibleResults[r],
666 visibleResults[r + 1],
667 (visibleResults[r] - startRes) * av.charWidth,
668 offset + ( (i - startSeq) * av.charHeight));
672 if(av.cursorMode && cursorY==i
673 && cursorX>=startRes && cursorX<=endRes)
675 sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * av.charWidth,
676 offset + ( (i - startSeq) * av.charHeight));
680 if(av.getSelectionGroup()!=null || av.alignment.getGroups().size()>0)
681 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
685 void drawGroupsBoundaries(Graphics g1,
686 int startRes, int endRes,
687 int startSeq, int endSeq,
690 Graphics2D g = (Graphics2D)g1;
692 /////////////////////////////////////
693 // Now outline any areas if necessary
694 /////////////////////////////////////
695 SequenceGroup group = av.getSelectionGroup();
702 if ((group == null) && (av.alignment.getGroups().size() > 0))
704 group = (SequenceGroup) av.alignment.getGroups().elementAt(0);
714 boolean inGroup = false;
718 for (i = startSeq; i < endSeq; i++)
720 sx = (group.getStartRes() - startRes) * av.charWidth;
721 sy = offset + ((i - startSeq) * av.charHeight);
722 ex = (((group.getEndRes() + 1) - group.getStartRes()) * av.charWidth) -
725 if(sx+ex<0 || sx>imgWidth)
730 if ( (sx <= (endRes-startRes)*av.charWidth) &&
731 group.getSequences(false).
732 contains(av.alignment.getSequenceAt(i)))
734 if ((bottom == -1) &&
735 !group.getSequences(false).contains(
736 av.alignment.getSequenceAt(i + 1)))
738 bottom = sy + av.charHeight;
743 if (((top == -1) && (i == 0)) ||
744 !group.getSequences(false).contains(
745 av.alignment.getSequenceAt(i - 1)))
753 if (group == av.getSelectionGroup())
755 g.setStroke(new BasicStroke(1,
756 BasicStroke.CAP_BUTT,
757 BasicStroke.JOIN_ROUND, 3f,
758 new float[] { 5f, 3f }, 0f));
759 g.setColor(Color.RED);
763 g.setStroke(new BasicStroke());
764 g.setColor(group.getOutlineColour());
772 if (sx >= 0 && sx < imgWidth)
773 g.drawLine(sx, oldY, sx, sy);
775 if (sx + ex < imgWidth)
776 g.drawLine(sx + ex, oldY, sx + ex, sy);
784 if (sx + ex > imgWidth)
787 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
788 ex = (endRes - startRes + 1) * av.charWidth;
792 g.drawLine(sx, top, sx + ex, top);
798 g.drawLine(sx, bottom, sx + ex, bottom);
809 sy = offset + ( (i - startSeq) * av.charHeight);
810 if (sx >= 0 && sx < imgWidth)
811 g.drawLine(sx, oldY, sx, sy);
813 if (sx + ex < imgWidth)
814 g.drawLine(sx + ex, oldY, sx + ex, sy);
822 if (sx + ex > imgWidth)
824 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
825 ex = (endRes - startRes + 1) * av.charWidth;
829 g.drawLine(sx, top, sx + ex, top);
835 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
844 if (groupIndex >= av.alignment.getGroups().size())
849 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);
851 g.setStroke(new BasicStroke());
853 while (groupIndex < av.alignment.getGroups().size());
862 * @param results DOCUMENT ME!
864 public void highlightSearchResults(SearchResults results)
868 searchResults = results;