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 MCview.AppletPDBCanvas pdbCanvas;
\r
64 public SequenceRenderer getSequenceRenderer()
\r
69 public void setPDBCanvas(MCview.AppletPDBCanvas pc)
\r
74 void drawNorthScale(Graphics g, int startx, int endx, int ypos)
\r
76 int scalestartx = startx - startx % 10 + 10;
\r
78 g.setColor(Color.black);
\r
81 for (int i = scalestartx; i < endx; i += 10)
\r
84 if (av.hasHiddenColumns)
\r
86 value = av.getColumnSelection().adjustForHiddenColumns(value);
\r
89 g.drawString(String.valueOf(value), (i - startx - 1) * av.charWidth,
\r
90 ypos - (av.charHeight / 2));
\r
92 g.drawLine( ( (i - startx - 1) * av.charWidth) + (av.charWidth / 2),
\r
93 (ypos + 2) - (av.charHeight / 2),
\r
94 ( (i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -
\r
99 void drawWestScale(Graphics g, int startx, int endx, int ypos)
\r
101 FontMetrics fm = getFontMetrics(av.getFont());
\r
102 ypos += av.charHeight;
\r
103 if (av.hasHiddenColumns)
\r
105 startx = av.getColumnSelection().adjustForHiddenColumns(startx);
\r
106 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
\r
109 int maxwidth = av.alignment.getWidth();
\r
110 if (av.hasHiddenColumns)
\r
112 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
\r
116 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
118 SequenceI seq = av.alignment.getSequenceAt(i);
\r
119 int index = startx;
\r
122 while (index < endx)
\r
124 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
\r
131 value = av.alignment.getSequenceAt(i).findPosition(index);
\r
138 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value)) -
\r
140 g.drawString(value + "", x,
\r
141 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
\r
146 void drawEastScale(Graphics g, int startx, int endx, int ypos)
\r
148 ypos += av.charHeight;
\r
150 if (av.hasHiddenColumns)
\r
152 endx = av.getColumnSelection().adjustForHiddenColumns(endx);
\r
157 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
159 seq = av.alignment.getSequenceAt(i);
\r
163 while (index > startx)
\r
165 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
\r
172 value = seq.findPosition(index);
\r
179 g.drawString(String.valueOf(value), 0,
\r
180 (ypos + (i * av.charHeight)) - (av.charHeight / 5));
\r
186 void fastPaint(int horizontal, int vertical)
\r
188 if (fastPaint || gg == null)
\r
193 // Its possible on certain browsers that the call to fastpaint
\r
194 // is faster than it can paint, so this check here catches
\r
195 // this possibility
\r
196 if (lastsr + horizontal != av.startRes)
\r
198 horizontal = av.startRes - lastsr;
\r
201 lastsr = av.startRes;
\r
204 gg.copyArea(horizontal * av.charWidth,
\r
205 vertical * av.charHeight,
\r
206 imgWidth - horizontal * av.charWidth,
\r
207 imgHeight - vertical * av.charHeight,
\r
208 -horizontal * av.charWidth,
\r
209 -vertical * av.charHeight);
\r
211 int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq,
\r
212 transX = 0, transY = 0;
\r
214 if (horizontal > 0) // scrollbar pulled right, image to the left
\r
216 transX = (er - sr - horizontal) * av.charWidth;
\r
217 sr = er - horizontal;
\r
219 else if (horizontal < 0)
\r
221 er = sr - horizontal;
\r
224 else if (vertical > 0) // scroll down
\r
226 ss = es - vertical;
\r
227 if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
\r
233 transY = imgHeight - vertical * av.charHeight;
\r
236 else if (vertical < 0)
\r
238 es = ss - vertical;
\r
239 if (es > av.endSeq)
\r
245 gg.translate(transX, transY);
\r
247 drawPanel(gg, sr, er, ss, es, 0);
\r
248 gg.translate( -transX, -transY);
\r
255 * Definitions of startx and endx (hopefully):
\r
256 * SMJS This is what I'm working towards!
\r
257 * startx is the first residue (starting at 0) to display.
\r
258 * endx is the last residue to display (starting at 0).
\r
259 * starty is the first sequence to display (starting at 0).
\r
260 * endy is the last sequence to display (starting at 0).
\r
261 * NOTE 1: The av limits are set in setFont in this class and
\r
262 * in the adjustment listener in SeqPanel when the scrollbars move.
\r
264 public void update(Graphics g)
\r
269 public void paint(Graphics g)
\r
272 if (img != null && (fastPaint
\r
273 || (getSize().width != g.getClipBounds().width)
\r
274 || (getSize().height != g.getClipBounds().height)))
\r
276 g.drawImage(img, 0, 0, this);
\r
283 g.drawImage(img, 0, 0, this);
\r
288 // this draws the whole of the alignment
\r
289 imgWidth = this.getSize().width;
\r
290 imgHeight = this.getSize().height;
\r
292 imgWidth -= imgWidth % av.charWidth;
\r
293 imgHeight -= imgHeight % av.charHeight;
\r
295 if (imgWidth < 1 || imgHeight < 1)
\r
300 if (img == null || imgWidth != img.getWidth(this) ||
\r
301 imgHeight != img.getHeight(this))
\r
303 img = createImage(imgWidth, imgHeight);
\r
304 gg = img.getGraphics();
\r
305 gg.setFont(av.getFont());
\r
308 gg.setColor(Color.white);
\r
309 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
352 * Generates a string of zeroes.
\r
360 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
362 tmp = av.alignment.getSequenceAt(i).getEnd();
\r
363 if (tmp > maxWidth)
\r
369 for (int i = maxWidth; i > 0; i /= 10)
\r
376 public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,
\r
379 AlignmentI al = av.getAlignment();
\r
381 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
396 hgap += av.charHeight;
\r
399 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;
\r
400 int cHeight = av.getAlignment().getHeight() * av.charHeight;
\r
402 av.setWrappedWidth(cWidth);
\r
404 av.endRes = av.startRes + cWidth;
\r
409 int maxwidth = av.alignment.getWidth() - 1;
\r
411 if (av.hasHiddenColumns)
\r
413 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
\r
416 while ( (ypos <= canvasHeight) && (startRes < maxwidth))
\r
418 endx = startRes + cWidth - 1;
\r
420 if (endx > maxwidth)
\r
425 g.setColor(Color.black);
\r
427 if (av.scaleLeftWrapped)
\r
429 drawWestScale(g, startRes, endx, ypos);
\r
432 if (av.scaleRightWrapped)
\r
434 g.translate(canvasWidth - LABEL_EAST, 0);
\r
435 drawEastScale(g, startRes, endx, ypos);
\r
436 g.translate( - (canvasWidth - LABEL_EAST), 0);
\r
439 g.translate(LABEL_WEST, 0);
\r
441 if (av.scaleAboveWrapped)
\r
443 drawNorthScale(g, startRes, endx, ypos);
\r
445 if (av.hasHiddenColumns && av.showHiddenMarkers)
\r
447 g.setColor(Color.blue);
\r
449 for (int i = 0; i < av.getColumnSelection().getHiddenColumns().size();
\r
452 res = av.getColumnSelection().findHiddenRegionPosition(i) -
\r
455 if (res < 0 || res > endx - startRes)
\r
460 gg.fillPolygon(new int[]
\r
461 {res * av.charWidth - av.charHeight / 4,
\r
462 res * av.charWidth + av.charHeight / 4,
\r
463 res * av.charWidth},
\r
466 ypos - (av.charHeight / 2),
\r
467 ypos - (av.charHeight / 2),
\r
468 ypos - (av.charHeight / 2) + 8
\r
474 if (g.getClip() == null)
\r
476 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);
\r
479 drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);
\r
482 if (av.showAnnotation)
\r
484 g.translate(0, cHeight + ypos + 4);
\r
485 if (annotations == null)
\r
487 annotations = new AnnotationPanel(av);
\r
490 annotations.drawComponent(g, startRes, endx + 1);
\r
491 g.translate(0, -cHeight - ypos - 4);
\r
493 g.translate( -LABEL_WEST, 0);
\r
495 ypos += cHeight + getAnnotationHeight() + hgap;
\r
497 startRes += cWidth;
\r
502 AnnotationPanel annotations;
\r
503 int getAnnotationHeight()
\r
505 if (!av.showAnnotation)
\r
510 if (annotations == null)
\r
512 annotations = new AnnotationPanel(av);
\r
515 return annotations.adjustPanelHeight();
\r
518 void drawPanel(Graphics g1, int startRes, int endRes,
\r
519 int startSeq, int endSeq, int offset)
\r
521 if (!av.hasHiddenColumns)
\r
523 draw(g1, startRes, endRes, startSeq, endSeq, offset);
\r
527 java.util.Vector regions = av.getColumnSelection().getHiddenColumns();
\r
530 int blockStart = startRes;
\r
531 int blockEnd = endRes;
\r
533 for (int i = 0; i < regions.size(); i++)
\r
535 int[] region = (int[]) regions.elementAt(i);
\r
536 int hideStart = region[0];
\r
537 int hideEnd = region[1];
\r
539 if (hideStart <= blockStart)
\r
541 blockStart += (hideEnd - hideStart) + 1;
\r
545 blockEnd = hideStart - 1;
\r
547 g1.translate(screenY * av.charWidth, 0);
\r
549 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
551 if (av.getShowHiddenMarkers())
\r
553 g1.setColor(Color.blue);
\r
554 g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
556 (blockEnd - blockStart + 1) * av.charWidth - 1,
\r
557 (endSeq - startSeq) * av.charHeight + offset);
\r
560 g1.translate( -screenY * av.charWidth, 0);
\r
561 screenY += blockEnd - blockStart + 1;
\r
562 blockStart = hideEnd + 1;
\r
565 if (screenY <= (endRes - startRes))
\r
567 blockEnd = blockStart + (endRes - startRes) - screenY;
\r
568 g1.translate(screenY * av.charWidth, 0);
\r
569 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
\r
571 g1.translate( -screenY * av.charWidth, 0);
\r
577 //int startRes, int endRes, int startSeq, int endSeq, int x, int y,
\r
578 // int x1, int x2, int y1, int y2, int startx, int starty,
\r
579 void draw(Graphics g,
\r
580 int startRes, int endRes,
\r
581 int startSeq, int endSeq,
\r
584 g.setFont(av.getFont());
\r
585 sr.prepare(g, av.renderGaps);
\r
589 /// First draw the sequences
\r
590 /////////////////////////////
\r
591 for (int i = startSeq; i < endSeq; i++)
\r
593 nextSeq = av.alignment.getSequenceAt(i);
\r
595 if (nextSeq == null)
\r
600 sr.drawSequence(nextSeq, av.alignment.findAllGroups(nextSeq),
\r
602 offset + ( (i - startSeq) * av.charHeight));
\r
604 if (av.showSequenceFeatures)
\r
606 fr.drawSequence(g, nextSeq, startRes, endRes,
\r
607 offset + ( (i - startSeq) * av.charHeight));
\r
610 /// Highlight search Results once all sequences have been drawn
\r
611 //////////////////////////////////////////////////////////
\r
612 if (searchResults != null)
\r
614 int[] visibleResults = searchResults.getResults(nextSeq, startRes,
\r
616 if (visibleResults != null)
\r
618 for (int r = 0; r < visibleResults.length; r += 2)
\r
620 sr.drawHighlightedText(nextSeq, visibleResults[r],
\r
621 visibleResults[r + 1],
\r
622 (visibleResults[r] - startRes) *
\r
624 offset + ( (i - startSeq) * av.charHeight));
\r
629 if (av.cursorMode && cursorY == i
\r
630 && cursorX >= startRes && cursorX <= endRes)
\r
632 sr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * av.charWidth,
\r
633 offset + ( (i - startSeq) * av.charHeight));
\r
637 if (av.getSelectionGroup() != null || av.alignment.getGroups().size() > 0)
\r
639 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
\r
644 void drawGroupsBoundaries(Graphics g,
\r
645 int startRes, int endRes,
\r
646 int startSeq, int endSeq,
\r
650 /////////////////////////////////////
\r
651 // Now outline any areas if necessary
\r
652 /////////////////////////////////////
\r
653 SequenceGroup group = av.getSelectionGroup();
\r
658 int groupIndex = -1;
\r
660 if ( (group == null) && (av.alignment.getGroups().size() > 0))
\r
662 group = (SequenceGroup) av.alignment.getGroups().elementAt(0);
\r
672 boolean inGroup = false;
\r
675 int alHeight = av.alignment.getHeight() - 1;
\r
677 for (i = startSeq; i < endSeq; i++)
\r
679 sx = (group.getStartRes() - startRes) * av.charWidth;
\r
680 sy = offset + ( (i - startSeq) * av.charHeight);
\r
681 ex = ( ( (group.getEndRes() + 1) - group.getStartRes()) *
\r
685 if (sx + ex < 0 || sx > imgWidth)
\r
690 if ( (sx <= (endRes - startRes) * av.charWidth) &&
\r
691 group.getSequences(null).
\r
692 contains(av.alignment.getSequenceAt(i)))
\r
694 if ( (bottom == -1) &&
\r
696 !group.getSequences(null).contains(
\r
697 av.alignment.getSequenceAt(i + 1))))
\r
699 bottom = sy + av.charHeight;
\r
704 if ( ( (top == -1) && (i == 0)) ||
\r
705 !group.getSequences(null).contains(
\r
706 av.alignment.getSequenceAt(i - 1)))
\r
714 if (group == av.getSelectionGroup())
\r
716 g.setColor(Color.red);
\r
720 g.setColor(group.getOutlineColour());
\r
728 if (sx >= 0 && sx < imgWidth)
\r
730 g.drawLine(sx, oldY, sx, sy);
\r
733 if (sx + ex < imgWidth)
\r
735 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
744 if (sx + ex > imgWidth)
\r
749 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
751 ex = (endRes - startRes + 1) * av.charWidth;
\r
756 g.drawLine(sx, top, sx + ex, top);
\r
762 g.drawLine(sx, bottom, sx + ex, bottom);
\r
773 sy = offset + ( (i - startSeq) * av.charHeight);
\r
774 if (sx >= 0 && sx < imgWidth)
\r
776 g.drawLine(sx, oldY, sx, sy);
\r
779 if (sx + ex < imgWidth)
\r
781 g.drawLine(sx + ex, oldY, sx + ex, sy);
\r
790 if (sx + ex > imgWidth)
\r
794 else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)
\r
796 ex = (endRes - startRes + 1) * av.charWidth;
\r
801 g.drawLine(sx, top, sx + ex, top);
\r
807 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
\r
816 if (groupIndex >= av.alignment.getGroups().size())
\r
821 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);
\r
823 while (groupIndex < av.alignment.getGroups().size());
\r
828 public void highlightSearchResults(SearchResults results)
\r
830 searchResults = results;
\r