2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2007 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
45 public SeqCanvas(AlignViewport av)
\r
48 fr = new FeatureRenderer(av);
\r
49 sr = new SequenceRenderer(av);
\r
50 PaintRefresher.Register(this, av.getSequenceSetId());
\r
53 public AlignViewport getViewport()
\r
58 public FeatureRenderer getFeatureRenderer()
\r
63 public SequenceRenderer getSequenceRenderer()
\r
68 void drawNorthScale(Graphics g, int startx, int endx, int ypos)
\r
70 int scalestartx = startx - startx % 10 + 10;
\r
72 g.setColor(Color.black);
\r
75 for (int i = scalestartx; i < endx; i += 10)
\r
78 if (av.hasHiddenColumns)
\r
80 value = av.getColumnSelection().adjustForHiddenColumns(value);
\r
83 g.drawString(String.valueOf(value), (i - startx - 1) * av.charWidth,
\r
84 ypos - (av.charHeight / 2));
\r
86 g.drawLine( ( (i - startx - 1) * av.charWidth) + (av.charWidth / 2),
\r
87 (ypos + 2) - (av.charHeight / 2),
\r
88 ( (i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -
\r
93 void drawWestScale(Graphics g, int startx, int endx, int ypos)
\r
95 FontMetrics fm = getFontMetrics(av.getFont());
\r
96 ypos += av.charHeight;
\r
97 if (av.hasHiddenColumns)
\r
99 startx = av.getColumnSelection().adjustForHiddenColumns(startx);
\r
100 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
\r
103 int maxwidth = av.alignment.getWidth();
\r
104 if (av.hasHiddenColumns)
\r
106 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
\r
110 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
112 SequenceI seq = av.alignment.getSequenceAt(i);
\r
113 int index = startx;
\r
116 while (index < endx)
\r
118 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
\r
125 value = av.alignment.getSequenceAt(i).findPosition(index);
\r
132 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value)) -
\r
134 g.drawString(value + "", x,
\r
135 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
\r
140 void drawEastScale(Graphics g, int startx, int endx, int ypos)
\r
142 ypos += av.charHeight;
\r
144 if (av.hasHiddenColumns)
\r
146 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
\r
151 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
153 seq = av.alignment.getSequenceAt(i);
\r
157 while (index > startx)
\r
159 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
\r
166 value = seq.findPosition(index);
\r
173 g.drawString(String.valueOf(value), 0,
\r
174 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
\r
180 void fastPaint(int horizontal, int vertical)
\r
182 if (fastPaint || gg == null)
\r
187 // Its possible on certain browsers that the call to fastpaint
\r
188 // is faster than it can paint, so this check here catches
\r
189 // this possibility
\r
190 if (lastsr + horizontal != av.startRes)
\r
192 horizontal = av.startRes - lastsr;
\r
195 lastsr = av.startRes;
\r
198 gg.copyArea(horizontal * av.charWidth,
\r
199 vertical * av.charHeight,
\r
200 imgWidth - horizontal * av.charWidth,
\r
201 imgHeight - vertical * av.charHeight,
\r
202 -horizontal * av.charWidth,
\r
203 -vertical * av.charHeight);
\r
205 int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq,
\r
206 transX = 0, transY = 0;
\r
208 if (horizontal > 0) // scrollbar pulled right, image to the left
\r
210 transX = (er - sr - horizontal) * av.charWidth;
\r
211 sr = er - horizontal;
\r
213 else if (horizontal < 0)
\r
215 er = sr - horizontal;
\r
218 else if (vertical > 0) // scroll down
\r
220 ss = es - vertical;
\r
221 if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
\r
227 transY = imgHeight - vertical * av.charHeight;
\r
230 else if (vertical < 0)
\r
232 es = ss - vertical;
\r
233 if (es > av.endSeq)
\r
239 gg.translate(transX, transY);
\r
241 drawPanel(gg, sr, er, ss, es, 0);
\r
242 gg.translate( -transX, -transY);
\r
249 * Definitions of startx and endx (hopefully):
\r
250 * SMJS This is what I'm working towards!
\r
251 * startx is the first residue (starting at 0) to display.
\r
252 * endx is the last residue to display (starting at 0).
\r
253 * starty is the first sequence to display (starting at 0).
\r
254 * endy is the last sequence to display (starting at 0).
\r
255 * NOTE 1: The av limits are set in setFont in this class and
\r
256 * in the adjustment listener in SeqPanel when the scrollbars move.
\r
258 public void update(Graphics g)
\r
263 public void paint(Graphics g)
\r
266 if (img != null && (fastPaint
\r
267 || (getSize().width != g.getClipBounds().width)
\r
268 || (getSize().height != g.getClipBounds().height)))
\r
270 g.drawImage(img, 0, 0, this);
\r
277 g.drawImage(img, 0, 0, this);
\r
282 // this draws the whole of the alignment
\r
283 imgWidth = this.getSize().width;
\r
284 imgHeight = this.getSize().height;
\r
286 imgWidth -= imgWidth % av.charWidth;
\r
287 imgHeight -= imgHeight % av.charHeight;
\r
289 if (imgWidth < 1 || imgHeight < 1)
\r
294 if (img == null || imgWidth != img.getWidth(this) ||
\r
295 imgHeight != img.getHeight(this))
\r
297 img = createImage(imgWidth, imgHeight);
\r
298 gg = img.getGraphics();
\r
299 gg.setFont(av.getFont());
\r
302 gg.setColor(Color.white);
\r
303 gg.fillRect(0, 0, imgWidth, imgHeight);
\r
305 if (av.getWrapAlignment())
\r
307 drawWrappedPanel(gg, imgWidth, imgHeight, av.startRes);
\r
311 drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);
\r
314 g.drawImage(img, 0, 0, this);
\r
318 int LABEL_WEST, LABEL_EAST;
\r
319 public int getWrappedCanvasWidth(int cwidth)
\r
321 cwidth -= cwidth % av.charWidth;
\r
323 FontMetrics fm = getFontMetrics(av.getFont());
\r
328 if (av.scaleRightWrapped)
\r
330 LABEL_EAST = fm.stringWidth(getMask());
\r
333 if (av.scaleLeftWrapped)
\r
335 LABEL_WEST = fm.stringWidth(getMask());
\r
338 return (cwidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
\r
342 * Generates a string of zeroes.
\r
350 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
352 tmp = av.alignment.getSequenceAt(i).getEnd();
\r
353 if (tmp > maxWidth)
\r
359 for (int i = maxWidth; 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
373 if (av.scaleRightWrapped)
\r
375 LABEL_EAST = fm.stringWidth(getMask());
\r
378 if (av.scaleLeftWrapped)
\r
380 LABEL_WEST = fm.stringWidth(getMask());
\r
383 int hgap = av.charHeight;
\r
384 if (av.scaleAboveWrapped)
\r
386 hgap += av.charHeight;
\r
389 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
\r
390 int cHeight = av.getAlignment().getHeight() * av.charHeight;
\r
392 av.setWrappedWidth(cWidth);
\r
394 av.endRes = av.startRes + cWidth;
\r
399 int maxwidth = av.alignment.getWidth() - 1;
\r
401 if (av.hasHiddenColumns)
\r
403 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
\r
406 while ( (ypos <= canvasHeight) && (startRes < maxwidth))
\r
408 endx = startRes + cWidth - 1;
\r
410 if (endx > maxwidth)
\r
415 g.setColor(Color.black);
\r
417 if (av.scaleLeftWrapped)
\r
419 drawWestScale(g, startRes, endx, ypos);
\r
422 if (av.scaleRightWrapped)
\r
424 g.translate(canvasWidth - LABEL_EAST, 0);
\r
425 drawEastScale(g, startRes, endx, ypos);
\r
426 g.translate( - (canvasWidth - LABEL_EAST), 0);
\r
429 g.translate(LABEL_WEST, 0);
\r
431 if (av.scaleAboveWrapped)
\r
433 drawNorthScale(g, startRes, endx, ypos);
\r
435 if (av.hasHiddenColumns && av.showHiddenMarkers)
\r
437 g.setColor(Color.blue);
\r
439 for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size();
\r
442 res = av.getColumnSelection().findHiddenRegionPosition(i) -
\r
445 if (res < 0 || res > endx - startRes)
\r
450 gg.fillPolygon(new int[]
\r
451 {res * av.charWidth - av.charHeight / 4,
\r
452 res * av.charWidth + av.charHeight / 4,
\r
453 res * av.charWidth},
\r
456 ypos - (av.charHeight / 2),
\r
457 ypos - (av.charHeight / 2),
\r
458 ypos - (av.charHeight / 2) + 8
\r
464 if (g.getClip() == null)
\r
466 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);
\r
469 drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
\r
472 if (av.showAnnotation)
\r
474 g.translate(0, cHeight + ypos + 4);
\r
475 if (annotations == null)
\r
477 annotations = new AnnotationPanel(av);
\r
480 annotations.drawComponent(g, startRes, endx + 1);
\r
481 g.translate(0, -cHeight - ypos - 4);
\r
483 g.translate( -LABEL_WEST, 0);
\r
485 ypos += cHeight + getAnnotationHeight() + hgap;
\r
487 startRes += cWidth;
\r
492 AnnotationPanel annotations;
\r
493 int getAnnotationHeight()
\r
495 if (!av.showAnnotation)
\r
500 if (annotations == null)
\r
502 annotations = new AnnotationPanel(av);
\r
505 return annotations.adjustPanelHeight();
\r
508 void drawPanel(Graphics g1, int startRes, int endRes,
\r
509 int startSeq, int endSeq, int offset)
\r
511 if (!av.hasHiddenColumns)
\r
513 draw(g1, startRes, endRes, startSeq, endSeq, offset);
\r
517 java.util.Vector regions = av.getColumnSelection().getHiddenColumns();
\r
520 int blockStart = startRes;
\r
521 int blockEnd = endRes;
\r
523 for (int i = 0; i < regions.size(); i++)
\r
525 int[] region = (int[]) regions.elementAt(i);
\r
526 int hideStart = region[0];
\r
527 int hideEnd = region[1];
\r
529 if (hideStart <= blockStart)
\r
531 blockStart += (hideEnd - hideStart) + 1;
\r
535 blockEnd = hideStart - 1;
\r
537 g1.translate(screenY * av.charWidth, 0);
\r
539 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
541 if (av.getShowHiddenMarkers())
\r
543 g1.setColor(Color.blue);
\r
544 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
546 (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
547 (endSeq - startSeq) * av.charHeight + offset);
\r
550 g1.translate( -screenY * av.charWidth, 0);
\r
551 screenY += blockEnd - blockStart + 1;
\r
552 blockStart = hideEnd + 1;
\r
555 if (screenY <= (endRes - startRes))
\r
557 blockEnd = blockStart + (endRes - startRes) - screenY;
\r
558 g1.translate(screenY * av.charWidth, 0);
\r
559 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
561 g1.translate( -screenY * av.charWidth, 0);
\r
567 //int startRes, int endRes, int startSeq, int endSeq, int x, int y,
\r
568 // int x1, int x2, int y1, int y2, int startx, int starty,
\r
569 void draw(Graphics g,
\r
570 int startRes, int endRes,
\r
571 int startSeq, int endSeq,
\r
574 g.setFont(av.getFont());
\r
575 sr.prepare(g, av.renderGaps);
\r
579 /// First draw the sequences
\r
580 /////////////////////////////
\r
581 for (int i = startSeq; i < endSeq; i++)
\r
583 nextSeq = av.alignment.getSequenceAt(i);
\r
585 if (nextSeq == null)
\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,
\r
606 if (visibleResults != null)
\r
608 for (int r = 0; r < visibleResults.length; r += 2)
\r
610 sr.drawHighlightedText(nextSeq, visibleResults[r],
\r
611 visibleResults[r + 1],
\r
612 (visibleResults[r] - startRes) *
\r
614 offset + ( (i - startSeq) * av.charHeight));
\r
619 if (av.cursorMode && cursorY == i
\r
620 && cursorX >= startRes && cursorX <= endRes)
\r
622 sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * av.charWidth,
\r
623 offset + ( (i - startSeq) * av.charHeight));
\r
627 if (av.getSelectionGroup() != null || av.alignment.getGroups().size() > 0)
\r
629 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
\r
634 void drawGroupsBoundaries(Graphics g,
\r
635 int startRes, int endRes,
\r
636 int startSeq, int endSeq,
\r
640 /////////////////////////////////////
\r
641 // Now outline any areas if necessary
\r
642 /////////////////////////////////////
\r
643 SequenceGroup group = av.getSelectionGroup();
\r
648 int groupIndex = -1;
\r
650 if ( (group == null) && (av.alignment.getGroups().size() > 0))
\r
652 group = (SequenceGroup) av.alignment.getGroups().elementAt(0);
\r
662 boolean inGroup = false;
\r
665 int alHeight = av.alignment.getHeight() - 1;
\r
667 for (i = startSeq; i < endSeq; i++)
\r
669 sx = (group.getStartRes() - startRes) * av.charWidth;
\r
670 sy = offset + ( (i - startSeq) * av.charHeight);
\r
671 ex = ( ( (group.getEndRes() + 1) - group.getStartRes()) *
\r
675 if (sx + ex < 0 || sx > imgWidth)
\r
680 if ( (sx <= (endRes - startRes) * av.charWidth) &&
\r
681 group.getSequences(null).
\r
682 contains(av.alignment.getSequenceAt(i)))
\r
684 if ( (bottom == -1) &&
\r
686 !group.getSequences(null).contains(
\r
687 av.alignment.getSequenceAt(i + 1))))
\r
689 bottom = sy + av.charHeight;
\r
694 if ( ( (top == -1) && (i == 0)) ||
\r
695 !group.getSequences(null).contains(
\r
696 av.alignment.getSequenceAt(i - 1)))
\r
704 if (group == av.getSelectionGroup())
\r
706 g.setColor(Color.red);
\r
710 g.setColor(group.getOutlineColour());
\r
718 if (sx >= 0 && sx < imgWidth)
\r
720 g.drawLine(sx, oldY, sx, sy);
\r
723 if (sx + ex < imgWidth)
\r
725 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
734 if (sx + ex > imgWidth)
\r
739 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
741 ex = (endRes - startRes + 1) * av.charWidth;
\r
746 g.drawLine(sx, top, sx + ex, top);
\r
752 g.drawLine(sx, bottom, sx + ex, bottom);
\r
763 sy = offset + ( (i - startSeq) * av.charHeight);
\r
764 if (sx >= 0 && sx < imgWidth)
\r
766 g.drawLine(sx, oldY, sx, sy);
\r
769 if (sx + ex < imgWidth)
\r
771 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
780 if (sx + ex > imgWidth)
\r
784 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
786 ex = (endRes - startRes + 1) * av.charWidth;
\r
791 g.drawLine(sx, top, sx + ex, top);
\r
797 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
\r
806 if (groupIndex >= av.alignment.getGroups().size())
\r
811 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);
\r
813 while (groupIndex < av.alignment.getGroups().size());
\r
818 public void highlightSearchResults(SearchResults results)
\r
820 searchResults = results;
\r