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
20 package jalview.appletgui;
24 import jalview.datamodel.*;
26 public class SeqCanvas
38 SearchResults searchResults = null;
40 boolean fastPaint = false;
47 public SeqCanvas(AlignViewport av)
50 fr = new FeatureRenderer(av);
51 sr = new SequenceRenderer(av);
52 PaintRefresher.Register(this, av.alignment);
55 public AlignViewport getViewport()
60 public FeatureRenderer getFeatureRenderer()
65 MCview.AppletPDBCanvas pdbCanvas;
66 public SequenceRenderer getSequenceRenderer()
71 public void setPDBCanvas(MCview.AppletPDBCanvas pc)
77 void drawNorthScale(Graphics g, int startx, int endx, int ypos)
79 int scalestartx = startx - startx % 10 + 10;
81 g.setColor(Color.black);
84 for (int i = scalestartx; i < endx; i += 10)
87 if(av.hasHiddenColumns)
88 value = av.getColumnSelection().adjustForHiddenColumns(value);
90 g.drawString( String.valueOf(value), (i - startx - 1) * av.charWidth,
91 ypos - (av.charHeight / 2));
93 g.drawLine(((i - startx - 1) * av.charWidth) + (av.charWidth / 2),
94 (ypos + 2) - (av.charHeight / 2),
95 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -
100 void drawWestScale(Graphics g, int startx, int endx, int ypos)
102 FontMetrics fm = getFontMetrics(av.getFont());
103 ypos += av.charHeight;
104 if (av.hasHiddenColumns)
106 startx = av.getColumnSelection().adjustForHiddenColumns(startx);
107 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
110 int maxwidth = av.alignment.getWidth();
111 if (av.hasHiddenColumns)
112 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
115 for (int i = 0; i < av.alignment.getHeight(); i++)
117 SequenceI seq = av.alignment.getSequenceAt(i);
123 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
130 value = av.alignment.getSequenceAt(i).findPosition(index);
137 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value)) -
139 g.drawString(value + "", x,
140 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
144 void drawEastScale(Graphics g, int startx, int endx, int ypos)
146 ypos += av.charHeight;
148 if(av.hasHiddenColumns)
149 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
153 for (int i = 0; i < av.alignment.getHeight(); i++)
155 seq = av.alignment.getSequenceAt(i);
159 while (index > startx)
161 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
168 value = seq.findPosition(index);
175 g.drawString(String.valueOf(value), 0,
176 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
182 void fastPaint(int horizontal, int vertical)
184 if ( fastPaint || gg == null)
190 // Its possible on certain browsers that the call to fastpaint
191 // is faster than it can paint, so this check here catches
193 if(lastsr + horizontal != av.startRes)
195 horizontal = av.startRes - lastsr;
198 lastsr = av.startRes;
201 gg.copyArea(horizontal * av.charWidth,
202 vertical * av.charHeight,
203 imgWidth - horizontal * av.charWidth,
204 imgHeight - vertical * av.charHeight,
205 -horizontal * av.charWidth,
206 -vertical * av.charHeight);
210 int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq,
211 transX = 0, transY = 0;
213 if (horizontal > 0) // scrollbar pulled right, image to the left
215 transX = (er - sr - horizontal) * av.charWidth;
216 sr = er - horizontal;
218 else if (horizontal < 0)
220 er = sr - horizontal;
223 else if (vertical > 0) // scroll down
226 if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
232 transY = imgHeight - vertical * av.charHeight;
235 else if (vertical < 0)
244 gg.translate(transX, transY);
246 drawPanel(gg, sr, er, ss, es, 0);
247 gg.translate( -transX, -transY);
254 * Definitions of startx and endx (hopefully):
255 * SMJS This is what I'm working towards!
256 * startx is the first residue (starting at 0) to display.
257 * endx is the last residue to display (starting at 0).
258 * starty is the first sequence to display (starting at 0).
259 * endy is the last sequence to display (starting at 0).
260 * NOTE 1: The av limits are set in setFont in this class and
261 * in the adjustment listener in SeqPanel when the scrollbars move.
263 public void update(Graphics g)
268 public void paint(Graphics g)
271 if (img != null && (fastPaint
272 || (getSize().width != g.getClipBounds().width)
273 || (getSize().height != g.getClipBounds().height)))
275 g.drawImage(img, 0, 0, this);
282 g.drawImage(img, 0, 0, this);
287 // this draws the whole of the alignment
288 imgWidth = this.getSize().width;
289 imgHeight = this.getSize().height;
291 imgWidth -= imgWidth % av.charWidth;
292 imgHeight -= imgHeight % av.charHeight;
294 if (imgWidth < 1 || imgHeight < 1)
299 if (img == null || imgWidth != img.getWidth(this) ||
300 imgHeight != img.getHeight(this))
302 img = createImage(imgWidth, imgHeight);
303 gg = img.getGraphics();
304 gg.setFont(av.getFont());
307 gg.setColor(Color.white);
308 gg.fillRect(0, 0, imgWidth, imgHeight);
311 if (av.getWrapAlignment())
313 drawWrappedPanel(gg, imgWidth, imgHeight, av.startRes);
317 drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
320 g.drawImage(img, 0, 0, this);
322 if (pdbCanvas != null)
324 pdbCanvas.updateSeqColours();
328 int LABEL_WEST, LABEL_EAST;
329 public int getWrappedCanvasWidth(int cwidth)
331 cwidth -= cwidth % av.charWidth;
333 FontMetrics fm = getFontMetrics(av.getFont());
338 if (av.scaleRightWrapped)
340 LABEL_EAST = fm.stringWidth(getMask());
343 if (av.scaleLeftWrapped)
345 LABEL_WEST = fm.stringWidth(getMask());
348 return (cwidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
353 * Generates a string of zeroes.
359 for (int i = av.alignment.getWidth(); i > 0; i /= 10)
366 public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,
369 AlignmentI al = av.getAlignment();
371 FontMetrics fm = getFontMetrics(av.getFont());
374 if (av.scaleRightWrapped)
376 LABEL_EAST = fm.stringWidth(getMask());
379 if (av.scaleLeftWrapped)
381 LABEL_WEST = fm.stringWidth(getMask());
384 int hgap = av.charHeight;
385 if(av.scaleAboveWrapped)
386 hgap += av.charHeight;
388 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
389 int cHeight = av.getAlignment().getHeight() * av.charHeight;
391 av.setWrappedWidth(cWidth);
393 av.endRes = av.startRes + cWidth;
399 int maxwidth = av.alignment.getWidth();
401 if(av.hasHiddenColumns)
402 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth)-1;
404 while ((ypos <= canvasHeight) && (startRes < maxwidth))
406 endx = startRes + cWidth -1;
413 g.setColor(Color.black);
415 if (av.scaleLeftWrapped)
417 drawWestScale(g, startRes, endx, ypos);
420 if (av.scaleRightWrapped)
422 g.translate(canvasWidth - LABEL_EAST, 0);
423 drawEastScale(g, startRes, endx, ypos);
424 g.translate(-(canvasWidth - LABEL_EAST), 0);
427 g.translate(LABEL_WEST, 0);
429 if (av.scaleAboveWrapped)
431 drawNorthScale(g, startRes, endx, ypos);
433 if (av.hasHiddenColumns && av.showHiddenMarkers)
435 g.setColor(Color.blue);
437 for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size();
440 res = av.getColumnSelection().findHiddenRegionPosition(i) -
443 if (res < 0 || res > endx - startRes)
446 gg.fillPolygon(new int[]
447 {res * av.charWidth - av.charHeight / 4,
448 res * av.charWidth + av.charHeight / 4,
452 ypos - (av.charHeight / 2),
453 ypos - (av.charHeight / 2),
454 ypos - (av.charHeight / 2) + 8
460 if(g.getClip()==null)
461 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);
463 drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
467 if(av.showAnnotation)
469 g.translate(0, cHeight + ypos+4);
470 if(annotations==null)
471 annotations = new AnnotationPanel(av);
473 annotations.drawComponent( g, startRes, endx+1 );
474 g.translate(0, -cHeight - ypos-4);
476 g.translate(-LABEL_WEST, 0);
478 ypos += cHeight+getAnnotationHeight()+hgap;
486 AnnotationPanel annotations;
487 int getAnnotationHeight()
489 if(!av.showAnnotation)
492 if(annotations==null)
493 annotations = new AnnotationPanel(av);
495 return annotations.adjustPanelHeight();
498 void drawPanel(Graphics g1, int startRes, int endRes,
499 int startSeq, int endSeq, int offset)
501 if(!av.hasHiddenColumns)
503 draw(g1, startRes, endRes, startSeq, endSeq, offset);
507 java.util.Vector regions = av.getColumnSelection().getHiddenColumns();
510 int blockStart = startRes;
511 int blockEnd = endRes;
513 for (int i = 0; i < regions.size(); i++)
515 int[] region = (int[]) regions.elementAt(i);
516 int hideStart = region[0];
517 int hideEnd = region[1];
519 if (hideStart <= blockStart)
521 blockStart += (hideEnd - hideStart) + 1;
525 blockEnd = hideStart - 1;
527 g1.translate(screenY * av.charWidth, 0);
529 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
531 if(av.getShowHiddenMarkers())
533 g1.setColor(Color.blue);
534 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,
536 (blockEnd - blockStart + 1) * av.charWidth - 1,
537 startSeq + (endSeq - startSeq) * av.charHeight + offset);
540 g1.translate( -screenY * av.charWidth, 0);
541 screenY += blockEnd - blockStart + 1;
542 blockStart = hideEnd + 1;
545 if (screenY <= (endRes - startRes))
547 blockEnd = blockStart + (endRes - startRes) - screenY;
548 g1.translate(screenY * av.charWidth, 0);
549 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
551 g1.translate( -screenY * av.charWidth, 0);
560 //int startRes, int endRes, int startSeq, int endSeq, int x, int y,
561 // int x1, int x2, int y1, int y2, int startx, int starty,
562 void draw(Graphics g,
563 int startRes, int endRes,
564 int startSeq, int endSeq,
567 g.setFont(av.getFont());
568 sr.prepare(g, av.renderGaps);
572 /// First draw the sequences
573 /////////////////////////////
574 for (int i = startSeq; i < endSeq; i++)
576 nextSeq = av.alignment.getSequenceAt(i);
578 sr.drawSequence(nextSeq, av.alignment.findAllGroups(nextSeq),
580 offset + ( (i - startSeq) * av.charHeight));
582 if (av.showSequenceFeatures)
584 fr.drawSequence(g, nextSeq, startRes, endRes,
585 offset + ((i - startSeq) * av.charHeight));
588 /// Highlight search Results once all sequences have been drawn
589 //////////////////////////////////////////////////////////
590 if (searchResults != null)
592 int[] visibleResults = searchResults.getResults(nextSeq, startRes, endRes);
593 if (visibleResults != null)
594 for (int r = 0; r < visibleResults.length; r += 2)
596 sr.drawHighlightedText(nextSeq, visibleResults[r],
597 visibleResults[r + 1],
598 (visibleResults[r] - startRes) * av.charWidth,
599 offset + ( (i - startSeq) * av.charHeight));
603 if(av.cursorMode && cursorY==i
604 && cursorX>=startRes && cursorX<=endRes)
606 sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * av.charWidth,
607 offset + ( (i - startSeq) * av.charHeight));
611 if(av.getSelectionGroup()!=null || av.alignment.getGroups().size()>0)
612 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
616 void drawGroupsBoundaries(Graphics g,
617 int startRes, int endRes,
618 int startSeq, int endSeq,
622 /////////////////////////////////////
623 // Now outline any areas if necessary
624 /////////////////////////////////////
625 SequenceGroup group = av.getSelectionGroup();
632 if ( (group == null) && (av.alignment.getGroups().size() > 0))
634 group = (SequenceGroup) av.alignment.getGroups().elementAt(0);
644 boolean inGroup = false;
647 int alHeight = av.alignment.getHeight()-1;
649 for (i = startSeq; i < endSeq; i++)
651 sx = (group.getStartRes() - startRes) * av.charWidth;
652 sy = offset + ( (i - startSeq) * av.charHeight);
653 ex = ( ( (group.getEndRes() + 1) - group.getStartRes()) * av.charWidth) -
656 if (sx + ex < 0 || sx > imgWidth)
661 if ( (sx <= (endRes - startRes) * av.charWidth) &&
662 group.getSequences(false).
663 contains(av.alignment.getSequenceAt(i)))
665 if ( (bottom == -1) &&
667 !group.getSequences(false).contains(
668 av.alignment.getSequenceAt(i + 1))))
670 bottom = sy + av.charHeight;
675 if ( ( (top == -1) && (i == 0)) ||
676 !group.getSequences(false).contains(
677 av.alignment.getSequenceAt(i - 1)))
685 if (group == av.getSelectionGroup())
687 g.setColor(Color.red);
691 g.setColor(group.getOutlineColour());
699 if (sx >= 0 && sx < imgWidth)
700 g.drawLine(sx, oldY, sx, sy);
702 if (sx + ex < imgWidth)
703 g.drawLine(sx + ex, oldY, sx + ex, sy);
711 if (sx + ex > imgWidth)
714 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
715 ex = (endRes - startRes + 1) * av.charWidth;
719 g.drawLine(sx, top, sx + ex, top);
725 g.drawLine(sx, bottom, sx + ex, bottom);
736 sy = offset + ( (i - startSeq) * av.charHeight);
737 if (sx >= 0 && sx < imgWidth)
738 g.drawLine(sx, oldY, sx, sy);
740 if (sx + ex < imgWidth)
741 g.drawLine(sx + ex, oldY, sx + ex, sy);
749 if (sx + ex > imgWidth)
751 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
752 ex = (endRes - startRes + 1) * av.charWidth;
756 g.drawLine(sx, top, sx + ex, top);
762 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
771 if (groupIndex >= av.alignment.getGroups().size())
776 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);
778 while (groupIndex < av.alignment.getGroups().size());
783 public void highlightSearchResults(SearchResults results)
785 searchResults = results;