2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2006 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.getSequenceSetId());
\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
361 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
363 tmp = av.alignment.getSequenceAt(i).getEnd();
\r
364 if (tmp > maxWidth)
\r
368 for (int i = maxWidth; i > 0; i /= 10)
\r
375 public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,
\r
378 AlignmentI al = av.getAlignment();
\r
380 FontMetrics fm = getFontMetrics(av.getFont());
\r
383 if (av.scaleRightWrapped)
\r
385 LABEL_EAST = fm.stringWidth(getMask());
\r
388 if (av.scaleLeftWrapped)
\r
390 LABEL_WEST = fm.stringWidth(getMask());
\r
393 int hgap = av.charHeight;
\r
394 if(av.scaleAboveWrapped)
\r
395 hgap += av.charHeight;
\r
397 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
\r
398 int cHeight = av.getAlignment().getHeight() * av.charHeight;
\r
400 av.setWrappedWidth(cWidth);
\r
402 av.endRes = av.startRes + cWidth;
\r
408 int maxwidth = av.alignment.getWidth();
\r
410 if(av.hasHiddenColumns)
\r
411 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth)-1;
\r
413 while ((ypos <= canvasHeight) && (startRes < maxwidth))
\r
415 endx = startRes + cWidth -1;
\r
417 if (endx > maxwidth)
\r
422 g.setColor(Color.black);
\r
424 if (av.scaleLeftWrapped)
\r
426 drawWestScale(g, startRes, endx, ypos);
\r
429 if (av.scaleRightWrapped)
\r
431 g.translate(canvasWidth - LABEL_EAST, 0);
\r
432 drawEastScale(g, startRes, endx, ypos);
\r
433 g.translate(-(canvasWidth - LABEL_EAST), 0);
\r
436 g.translate(LABEL_WEST, 0);
\r
438 if (av.scaleAboveWrapped)
\r
440 drawNorthScale(g, startRes, endx, ypos);
\r
442 if (av.hasHiddenColumns && av.showHiddenMarkers)
\r
444 g.setColor(Color.blue);
\r
446 for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size();
\r
449 res = av.getColumnSelection().findHiddenRegionPosition(i) -
\r
452 if (res < 0 || res > endx - startRes)
\r
455 gg.fillPolygon(new int[]
\r
456 {res * av.charWidth - av.charHeight / 4,
\r
457 res * av.charWidth + av.charHeight / 4,
\r
458 res * av.charWidth},
\r
461 ypos - (av.charHeight / 2),
\r
462 ypos - (av.charHeight / 2),
\r
463 ypos - (av.charHeight / 2) + 8
\r
469 if(g.getClip()==null)
\r
470 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);
\r
472 drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
\r
476 if(av.showAnnotation)
\r
478 g.translate(0, cHeight + ypos+4);
\r
479 if(annotations==null)
\r
480 annotations = new AnnotationPanel(av);
\r
482 annotations.drawComponent( g, startRes, endx+1 );
\r
483 g.translate(0, -cHeight - ypos-4);
\r
485 g.translate(-LABEL_WEST, 0);
\r
487 ypos += cHeight+getAnnotationHeight()+hgap;
\r
490 startRes += cWidth;
\r
495 AnnotationPanel annotations;
\r
496 int getAnnotationHeight()
\r
498 if(!av.showAnnotation)
\r
501 if(annotations==null)
\r
502 annotations = new AnnotationPanel(av);
\r
504 return annotations.adjustPanelHeight();
\r
507 void drawPanel(Graphics g1, int startRes, int endRes,
\r
508 int startSeq, int endSeq, int offset)
\r
510 if(!av.hasHiddenColumns)
\r
512 draw(g1, startRes, endRes, startSeq, endSeq, offset);
\r
516 java.util.Vector regions = av.getColumnSelection().getHiddenColumns();
\r
519 int blockStart = startRes;
\r
520 int blockEnd = endRes;
\r
522 for (int i = 0; i < regions.size(); i++)
\r
524 int[] region = (int[]) regions.elementAt(i);
\r
525 int hideStart = region[0];
\r
526 int hideEnd = region[1];
\r
528 if (hideStart <= blockStart)
\r
530 blockStart += (hideEnd - hideStart) + 1;
\r
534 blockEnd = hideStart - 1;
\r
536 g1.translate(screenY * av.charWidth, 0);
\r
538 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
540 if(av.getShowHiddenMarkers())
\r
542 g1.setColor(Color.blue);
\r
543 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
545 (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
546 (endSeq - startSeq) * av.charHeight + offset);
\r
549 g1.translate( -screenY * av.charWidth, 0);
\r
550 screenY += blockEnd - blockStart + 1;
\r
551 blockStart = hideEnd + 1;
\r
554 if (screenY <= (endRes - startRes))
\r
556 blockEnd = blockStart + (endRes - startRes) - screenY;
\r
557 g1.translate(screenY * av.charWidth, 0);
\r
558 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
560 g1.translate( -screenY * av.charWidth, 0);
\r
569 //int startRes, int endRes, int startSeq, int endSeq, int x, int y,
\r
570 // int x1, int x2, int y1, int y2, int startx, int starty,
\r
571 void draw(Graphics g,
\r
572 int startRes, int endRes,
\r
573 int startSeq, int endSeq,
\r
576 g.setFont(av.getFont());
\r
577 sr.prepare(g, av.renderGaps);
\r
581 /// First draw the sequences
\r
582 /////////////////////////////
\r
583 for (int i = startSeq; i < endSeq; i++)
\r
585 nextSeq = av.alignment.getSequenceAt(i);
\r
590 sr.drawSequence(nextSeq, av.alignment.findAllGroups(nextSeq),
\r
592 offset + ( (i - startSeq) * av.charHeight));
\r
594 if (av.showSequenceFeatures)
\r
596 fr.drawSequence(g, nextSeq, startRes, endRes,
\r
597 offset + ((i - startSeq) * av.charHeight));
\r
600 /// Highlight search Results once all sequences have been drawn
\r
601 //////////////////////////////////////////////////////////
\r
602 if (searchResults != null)
\r
604 int[] visibleResults = searchResults.getResults(nextSeq, startRes, endRes);
\r
605 if (visibleResults != null)
\r
606 for (int r = 0; r < visibleResults.length; r += 2)
\r
608 sr.drawHighlightedText(nextSeq, visibleResults[r],
\r
609 visibleResults[r + 1],
\r
610 (visibleResults[r] - startRes) * av.charWidth,
\r
611 offset + ( (i - startSeq) * av.charHeight));
\r
615 if(av.cursorMode && cursorY==i
\r
616 && cursorX>=startRes && cursorX<=endRes)
\r
618 sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * av.charWidth,
\r
619 offset + ( (i - startSeq) * av.charHeight));
\r
623 if(av.getSelectionGroup()!=null || av.alignment.getGroups().size()>0)
\r
624 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
\r
628 void drawGroupsBoundaries(Graphics g,
\r
629 int startRes, int endRes,
\r
630 int startSeq, int endSeq,
\r
634 /////////////////////////////////////
\r
635 // Now outline any areas if necessary
\r
636 /////////////////////////////////////
\r
637 SequenceGroup group = av.getSelectionGroup();
\r
642 int groupIndex = -1;
\r
644 if ( (group == null) && (av.alignment.getGroups().size() > 0))
\r
646 group = (SequenceGroup) av.alignment.getGroups().elementAt(0);
\r
656 boolean inGroup = false;
\r
659 int alHeight = av.alignment.getHeight()-1;
\r
661 for (i = startSeq; i < endSeq; i++)
\r
663 sx = (group.getStartRes() - startRes) * av.charWidth;
\r
664 sy = offset + ( (i - startSeq) * av.charHeight);
\r
665 ex = ( ( (group.getEndRes() + 1) - group.getStartRes()) * av.charWidth) -
\r
668 if (sx + ex < 0 || sx > imgWidth)
\r
673 if ( (sx <= (endRes - startRes) * av.charWidth) &&
\r
674 group.getSequences(false).
\r
675 contains(av.alignment.getSequenceAt(i)))
\r
677 if ( (bottom == -1) &&
\r
679 !group.getSequences(false).contains(
\r
680 av.alignment.getSequenceAt(i + 1))))
\r
682 bottom = sy + av.charHeight;
\r
687 if ( ( (top == -1) && (i == 0)) ||
\r
688 !group.getSequences(false).contains(
\r
689 av.alignment.getSequenceAt(i - 1)))
\r
697 if (group == av.getSelectionGroup())
\r
699 g.setColor(Color.red);
\r
703 g.setColor(group.getOutlineColour());
\r
711 if (sx >= 0 && sx < imgWidth)
\r
712 g.drawLine(sx, oldY, sx, sy);
\r
714 if (sx + ex < imgWidth)
\r
715 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
723 if (sx + ex > imgWidth)
\r
726 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
727 ex = (endRes - startRes + 1) * av.charWidth;
\r
731 g.drawLine(sx, top, sx + ex, top);
\r
737 g.drawLine(sx, bottom, sx + ex, bottom);
\r
748 sy = offset + ( (i - startSeq) * av.charHeight);
\r
749 if (sx >= 0 && sx < imgWidth)
\r
750 g.drawLine(sx, oldY, sx, sy);
\r
752 if (sx + ex < imgWidth)
\r
753 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
761 if (sx + ex > imgWidth)
\r
763 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
764 ex = (endRes - startRes + 1) * av.charWidth;
\r
768 g.drawLine(sx, top, sx + ex, top);
\r
774 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
\r
783 if (groupIndex >= av.alignment.getGroups().size())
\r
788 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);
\r
790 while (groupIndex < av.alignment.getGroups().size());
\r
795 public void highlightSearchResults(SearchResults results)
\r
797 searchResults = results;
\r