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