2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.datamodel.AlignmentI;
24 import jalview.datamodel.HiddenColumns;
25 import jalview.datamodel.SearchResultsI;
26 import jalview.datamodel.SequenceGroup;
27 import jalview.datamodel.SequenceI;
28 import jalview.renderer.ScaleRenderer;
29 import jalview.renderer.ScaleRenderer.ScaleMark;
30 import jalview.viewmodel.ViewportListenerI;
31 import jalview.viewmodel.ViewportRanges;
33 import java.awt.AlphaComposite;
34 import java.awt.BasicStroke;
35 import java.awt.BorderLayout;
36 import java.awt.Color;
37 import java.awt.FontMetrics;
38 import java.awt.Graphics;
39 import java.awt.Graphics2D;
40 import java.awt.RenderingHints;
41 import java.awt.Shape;
42 import java.awt.image.BufferedImage;
43 import java.beans.PropertyChangeEvent;
44 import java.util.List;
46 import javax.swing.JComponent;
54 public class SeqCanvas extends JComponent implements ViewportListenerI
56 final FeatureRenderer fr;
58 final SequenceRenderer seqRdr;
66 boolean fastPaint = false;
80 boolean fastpainting = false;
83 * Creates a new SeqCanvas object.
88 public SeqCanvas(AlignmentPanel ap)
92 fr = new FeatureRenderer(ap);
93 seqRdr = new SequenceRenderer(av);
94 setLayout(new BorderLayout());
95 PaintRefresher.Register(this, av.getSequenceSetId());
96 setBackground(Color.white);
98 av.getRanges().addPropertyChangeListener(this);
101 public SequenceRenderer getSequenceRenderer()
106 public FeatureRenderer getFeatureRenderer()
111 private void updateViewport()
113 charHeight = av.getCharHeight();
114 charWidth = av.getCharWidth();
129 private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
132 for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx,
135 int mpos = mark.column; // (i - startx - 1)
140 String mstring = mark.text;
146 g.drawString(mstring, mpos * charWidth, ypos - (charHeight / 2));
148 g.drawLine((mpos * charWidth) + (charWidth / 2), (ypos + 2)
149 - (charHeight / 2), (mpos * charWidth) + (charWidth / 2),
167 void drawWestScale(Graphics g, int startx, int endx, int ypos)
169 FontMetrics fm = getFontMetrics(av.getFont());
172 if (av.hasHiddenColumns())
174 startx = av.getAlignment().getHiddenColumns()
175 .adjustForHiddenColumns(startx);
176 endx = av.getAlignment().getHiddenColumns()
177 .adjustForHiddenColumns(endx);
180 int maxwidth = av.getAlignment().getWidth();
181 if (av.hasHiddenColumns())
183 maxwidth = av.getAlignment().getHiddenColumns()
184 .findColumnPosition(maxwidth) - 1;
188 for (int i = 0; i < av.getAlignment().getHeight(); i++)
190 SequenceI seq = av.getAlignment().getSequenceAt(i);
196 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
203 value = av.getAlignment().getSequenceAt(i).findPosition(index);
210 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))
212 g.drawString(value + "", x, (ypos + (i * charHeight))
230 void drawEastScale(Graphics g, int startx, int endx, int ypos)
234 if (av.hasHiddenColumns())
236 endx = av.getAlignment().getHiddenColumns()
237 .adjustForHiddenColumns(endx);
242 for (int i = 0; i < av.getAlignment().getHeight(); i++)
244 seq = av.getAlignment().getSequenceAt(i);
248 while (index > startx)
250 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
257 value = seq.findPosition(index);
264 g.drawString(String.valueOf(value), 0, (ypos + (i * charHeight))
272 * need to make this thread safe move alignment rendering in response to
278 * shift up or down in repaint
280 public void fastPaint(int horizontal, int vertical)
282 if (fastpainting || gg == null)
290 ViewportRanges ranges = av.getRanges();
291 int sr = ranges.getStartRes();
292 int er = ranges.getEndRes();
293 int ss = ranges.getStartSeq();
294 int es = ranges.getEndSeq();
298 gg.copyArea(horizontal * charWidth, vertical * charHeight,
299 img.getWidth(), img.getHeight(), -horizontal * charWidth,
300 -vertical * charHeight);
302 if (horizontal > 0) // scrollbar pulled right, image to the left
304 transX = (er - sr - horizontal) * charWidth;
305 sr = er - horizontal;
307 else if (horizontal < 0)
309 er = sr - horizontal;
311 else if (vertical > 0) // scroll down
315 if (ss < ranges.getStartSeq())
316 { // ie scrolling too fast, more than a page at a time
317 ss = ranges.getStartSeq();
321 transY = img.getHeight() - ((vertical + 1) * charHeight);
324 else if (vertical < 0)
328 if (es > ranges.getEndSeq())
330 es = ranges.getEndSeq();
334 gg.translate(transX, transY);
335 drawPanel(gg, sr, er, ss, es, 0);
336 gg.translate(-transX, -transY);
339 fastpainting = false;
343 * Definitions of startx and endx (hopefully): SMJS This is what I'm working
344 * towards! startx is the first residue (starting at 0) to display. endx is
345 * the last residue to display (starting at 0). starty is the first sequence
346 * to display (starting at 0). endy is the last sequence to display (starting
347 * at 0). NOTE 1: The av limits are set in setFont in this class and in the
348 * adjustment listener in SeqPanel when the scrollbars move.
351 // Set this to false to force a full panel paint
353 public void paintComponent(Graphics g)
355 super.paintComponent(g);
359 ViewportRanges ranges = av.getRanges();
361 int width = getWidth();
362 int height = getHeight();
364 width -= (width % charWidth);
365 height -= (height % charHeight);
367 // selectImage is the selection group outline image
368 BufferedImage selectImage = drawSelectionGroup(
369 ranges.getStartRes(), ranges.getEndRes(),
370 ranges.getStartSeq(), ranges.getEndSeq());
372 if (fastPaint || (getVisibleRect().width != g.getClipBounds().width)
373 || (getVisibleRect().height != g.getClipBounds().height))
375 BufferedImage lcimg = buildLocalImage(selectImage);
376 g.drawImage(lcimg, 0, 0, this);
379 else if ((width > 0) && (height > 0))
381 // img is a cached version of the last view we drew, if any
382 // if we have no img or the size has changed, make a new one
383 if (img == null || width != img.getWidth()
384 || height != img.getHeight())
391 gg = (Graphics2D) img.getGraphics();
392 gg.setFont(av.getFont());
397 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
398 RenderingHints.VALUE_ANTIALIAS_ON);
401 gg.setColor(Color.white);
402 gg.fillRect(0, 0, img.getWidth(), img.getHeight());
404 if (av.getWrapAlignment())
406 drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
410 drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
411 ranges.getStartSeq(), ranges.getEndSeq(), 0);
414 // lcimg is a local *copy* of img which we'll draw selectImage on top of
415 BufferedImage lcimg = buildLocalImage(selectImage);
416 g.drawImage(lcimg, 0, 0, this);
421 * Make a local image by combining the cached image img
424 private BufferedImage buildLocalImage(BufferedImage selectImage)
426 // clone the cached image
427 BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(),
429 Graphics2D g2d = lcimg.createGraphics();
430 g2d.drawImage(img, 0, 0, null);
432 // overlay selection group on lcimg
433 if (selectImage != null)
436 AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
437 g2d.drawImage(selectImage, 0, 0, this);
444 private void paintSeqGroup()
450 private BufferedImage setupImage()
452 BufferedImage lcimg = null;
454 int width = getWidth();
455 int height = getHeight();
457 width -= (width % charWidth);
458 height -= (height % charHeight);
460 if ((width < 1) || (height < 1))
467 lcimg = new BufferedImage(width, height,
468 BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
469 } catch (OutOfMemoryError er)
473 "Selection Group image OutOfMemory Redraw Error.\n" + er);
474 new OOMWarning("Creating alignment image for display", er);
488 * @return DOCUMENT ME!
490 public int getWrappedCanvasWidth(int cwidth)
492 FontMetrics fm = getFontMetrics(av.getFont());
497 if (av.getScaleRightWrapped())
499 LABEL_EAST = fm.stringWidth(getMask());
502 if (av.getScaleLeftWrapped())
504 LABEL_WEST = fm.stringWidth(getMask());
507 return (cwidth - LABEL_EAST - LABEL_WEST) / charWidth;
511 * Generates a string of zeroes.
520 for (int i = 0; i < av.getAlignment().getHeight(); i++)
522 tmp = av.getAlignment().getSequenceAt(i).getEnd();
529 for (int i = maxWidth; i > 0; i /= 10)
543 * @param canvasHeight
548 public void drawWrappedPanel(Graphics g, int canvasWidth,
549 int canvasHeight, int startRes)
552 AlignmentI al = av.getAlignment();
554 FontMetrics fm = getFontMetrics(av.getFont());
559 if (av.getScaleRightWrapped())
561 LABEL_EAST = fm.stringWidth(getMask());
564 if (av.getScaleLeftWrapped())
566 LABEL_WEST = fm.stringWidth(getMask());
569 int hgap = charHeight;
570 if (av.getScaleAboveWrapped())
575 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth;
576 int cHeight = av.getAlignment().getHeight() * charHeight;
578 av.setWrappedWidth(cWidth);
580 av.getRanges().setViewportStartAndWidth(startRes, cWidth);
584 int maxwidth = av.getAlignment().getWidth();
586 if (av.hasHiddenColumns())
588 maxwidth = av.getAlignment().getHiddenColumns()
589 .findColumnPosition(maxwidth);
592 while ((ypos <= canvasHeight) && (startRes < maxwidth))
594 endx = startRes + cWidth - 1;
601 g.setFont(av.getFont());
602 g.setColor(Color.black);
604 if (av.getScaleLeftWrapped())
606 drawWestScale(g, startRes, endx, ypos);
609 if (av.getScaleRightWrapped())
611 g.translate(canvasWidth - LABEL_EAST, 0);
612 drawEastScale(g, startRes, endx, ypos);
613 g.translate(-(canvasWidth - LABEL_EAST), 0);
616 g.translate(LABEL_WEST, 0);
618 if (av.getScaleAboveWrapped())
620 drawNorthScale(g, startRes, endx, ypos);
623 if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
625 g.setColor(Color.blue);
627 HiddenColumns hidden = av.getAlignment().getHiddenColumns();
628 List<Integer> positions = hidden.findHiddenRegionPositions();
629 for (int pos : positions)
631 res = pos - startRes;
633 if (res < 0 || res > endx - startRes)
639 new int[] { res * charWidth - charHeight / 4,
640 res * charWidth + charHeight / 4, res * charWidth },
641 new int[] { ypos - (charHeight / 2),
642 ypos - (charHeight / 2), ypos - (charHeight / 2) + 8 },
648 // When printing we have an extra clipped region,
649 // the Printable page which we need to account for here
650 Shape clip = g.getClip();
654 g.setClip(0, 0, cWidth * charWidth, canvasHeight);
658 g.setClip(0, (int) clip.getBounds().getY(), cWidth * charWidth,
659 (int) clip.getBounds().getHeight());
662 drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
664 if (av.isShowAnnotation())
666 g.translate(0, cHeight + ypos + 3);
667 if (annotations == null)
669 annotations = new AnnotationPanel(av);
672 annotations.renderer.drawComponent(annotations, av, g, -1,
674 g.translate(0, -cHeight - ypos - 3);
677 g.translate(-LABEL_WEST, 0);
679 ypos += cHeight + getAnnotationHeight() + hgap;
686 * Draw a selection group over a wrapped alignment
688 private void drawWrappedSelection(Graphics2D g, SequenceGroup group,
690 int canvasHeight, int startRes)
692 // height gap above each panel
693 int hgap = charHeight;
694 if (av.getScaleAboveWrapped())
699 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth;
700 int cHeight = av.getAlignment().getHeight() * charHeight;
702 int startx = startRes;
704 int ypos = hgap; // vertical offset
705 int maxwidth = av.getAlignment().getWidth();
707 if (av.hasHiddenColumns())
709 maxwidth = av.getAlignment().getHiddenColumns()
710 .findColumnPosition(maxwidth);
713 // chop the wrapped alignment extent up into panel-sized blocks and treat
714 // each block as if it were a block from an unwrapped alignment
715 while ((ypos <= canvasHeight) && (startx < maxwidth))
717 // set end value to be start + width, or maxwidth, whichever is smaller
718 endx = startx + cWidth - 1;
725 g.translate(LABEL_WEST, 0);
727 drawUnwrappedSelection(g, group, startx, endx, 0,
728 av.getAlignment().getHeight() - 1,
731 g.translate(-LABEL_WEST, 0);
733 // update vertical offset
734 ypos += cHeight + getAnnotationHeight() + hgap;
736 // update horizontal offset
741 AnnotationPanel annotations;
743 int getAnnotationHeight()
745 if (!av.isShowAnnotation())
750 if (annotations == null)
752 annotations = new AnnotationPanel(av);
755 return annotations.adjustPanelHeight();
774 public void drawPanel(Graphics g1, int startRes, int endRes,
775 int startSeq, int endSeq, int offset)
778 if (!av.hasHiddenColumns())
780 draw(g1, startRes, endRes, startSeq, endSeq, offset);
785 int blockStart = startRes;
786 int blockEnd = endRes;
788 for (int[] region : av.getAlignment().getHiddenColumns()
789 .getHiddenColumnsCopy())
791 int hideStart = region[0];
792 int hideEnd = region[1];
794 if (hideStart <= blockStart)
796 blockStart += (hideEnd - hideStart) + 1;
800 blockEnd = hideStart - 1;
802 g1.translate(screenY * charWidth, 0);
804 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
806 if (av.getShowHiddenMarkers())
808 g1.setColor(Color.blue);
810 g1.drawLine((blockEnd - blockStart + 1) * charWidth - 1,
811 0 + offset, (blockEnd - blockStart + 1) * charWidth - 1,
812 (endSeq - startSeq + 1) * charHeight + offset);
815 g1.translate(-screenY * charWidth, 0);
816 screenY += blockEnd - blockStart + 1;
817 blockStart = hideEnd + 1;
819 if (screenY > (endRes - startRes))
821 // already rendered last block
826 if (screenY <= (endRes - startRes))
828 // remaining visible region to render
829 blockEnd = blockStart + (endRes - startRes) - screenY;
830 g1.translate(screenY * charWidth, 0);
831 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
833 g1.translate(-screenY * charWidth, 0);
839 private void draw(Graphics g, int startRes, int endRes, int startSeq,
840 int endSeq, int offset)
842 g.setFont(av.getFont());
843 seqRdr.prepare(g, av.isRenderGaps());
847 // / First draw the sequences
848 // ///////////////////////////
849 for (int i = startSeq; i <= endSeq; i++)
851 nextSeq = av.getAlignment().getSequenceAt(i);
854 // occasionally, a race condition occurs such that the alignment row is
858 seqRdr.drawSequence(nextSeq, av.getAlignment().findAllGroups(nextSeq),
859 startRes, endRes, offset + ((i - startSeq) * charHeight));
861 if (av.isShowSequenceFeatures())
863 fr.drawSequence(g, nextSeq, startRes, endRes, offset
864 + ((i - startSeq) * charHeight), false);
867 // / Highlight search Results once all sequences have been drawn
868 // ////////////////////////////////////////////////////////
869 if (av.hasSearchResults())
871 int[] visibleResults = av.getSearchResults().getResults(nextSeq,
873 if (visibleResults != null)
875 for (int r = 0; r < visibleResults.length; r += 2)
877 seqRdr.drawHighlightedText(nextSeq, visibleResults[r],
878 visibleResults[r + 1], (visibleResults[r] - startRes)
880 + ((i - startSeq) * charHeight));
885 if (av.cursorMode && cursorY == i && cursorX >= startRes
886 && cursorX <= endRes)
888 seqRdr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
889 offset + ((i - startSeq) * charHeight));
893 if (av.getSelectionGroup() != null
894 || av.getAlignment().getGroups().size() > 0)
896 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
901 void drawGroupsBoundaries(Graphics g1, int startRes, int endRes,
902 int startSeq, int endSeq, int offset)
904 Graphics2D g = (Graphics2D) g1;
906 // ///////////////////////////////////
907 // Now outline any areas if necessary
908 // ///////////////////////////////////
910 SequenceGroup group = null;
916 int visWidth = (endRes - startRes + 1) * charWidth;
918 if (av.getAlignment().getGroups().size() > 0)
920 group = av.getAlignment().getGroups().get(0);
926 g.setStroke(new BasicStroke());
927 g.setColor(group.getOutlineColour());
932 // drawSelectionGroupPart(g, group, startRes, endRes, startSeq,
936 boolean inGroup = false;
940 for (i = startSeq; i <= endSeq; i++)
942 // position of start residue of group relative to startRes, in pixels
943 sx = (group.getStartRes() - startRes) * charWidth;
944 sy = offset + ((i - startSeq) * charHeight);
945 // width of group in pixels
946 ex = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
949 if (sx + ex < 0 || sx > visWidth)
954 if ((sx <= (endRes - startRes) * charWidth)
955 && group.getSequences(null).contains(
956 av.getAlignment().getSequenceAt(i)))
959 && !group.getSequences(null).contains(
960 av.getAlignment().getSequenceAt(i + 1)))
962 bottom = sy + charHeight;
967 if (((top == -1) && (i == 0))
968 || !group.getSequences(null).contains(
969 av.getAlignment().getSequenceAt(i - 1)))
977 g.setStroke(new BasicStroke());
978 g.setColor(group.getOutlineColour());
985 // if start position is visible, draw vertical line to left of
987 if (sx >= 0 && sx < visWidth)
989 g.drawLine(sx, oldY, sx, sy);
992 // if end position is visible, draw vertical line to right of
994 if (sx + ex < visWidth)
996 g.drawLine(sx + ex, oldY, sx + ex, sy);
1005 if (sx + ex > visWidth)
1009 else if (sx + ex >= (endRes - startRes + 1) * charWidth)
1011 ex = (endRes - startRes + 1) * charWidth;
1014 // draw horizontal line at top of group
1017 g.drawLine(sx, top, sx + ex, top);
1021 // draw horizontal line at bottom of group
1024 g.drawLine(sx, bottom, sx + ex, bottom);
1035 sy = offset + ((i - startSeq) * charHeight);
1036 if (sx >= 0 && sx < visWidth)
1038 g.drawLine(sx, oldY, sx, sy);
1041 if (sx + ex < visWidth)
1043 g.drawLine(sx + ex, oldY, sx + ex, sy);
1052 if (sx + ex > visWidth)
1056 else if (sx + ex >= (endRes - startRes + 1) * charWidth)
1058 ex = (endRes - startRes + 1) * charWidth;
1063 g.drawLine(sx, top, sx + ex, top);
1069 g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);
1078 g.setStroke(new BasicStroke());
1080 if (groupIndex >= av.getAlignment().getGroups().size())
1085 group = av.getAlignment().getGroups().get(groupIndex);
1087 } while (groupIndex < av.getAlignment().getGroups().size());
1095 * Draw the selection group as a separate image and overlay
1097 private BufferedImage drawSelectionGroup(int startRes, int endRes,
1098 int startSeq, int endSeq)
1100 // get a new image of the correct size
1101 BufferedImage selectionImage = setupImage();
1103 if (selectionImage == null)
1108 SequenceGroup group = av.getSelectionGroup();
1115 // set up drawing colour
1116 Graphics2D g = (Graphics2D) selectionImage.getGraphics();
1118 // set background to transparent
1119 g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
1120 g.fillRect(0, 0, selectionImage.getWidth(), selectionImage.getHeight());
1122 // set up foreground to draw red dashed line
1123 g.setComposite(AlphaComposite.Src);
1124 g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
1125 BasicStroke.JOIN_ROUND, 3f, new float[]
1127 g.setColor(Color.RED);
1129 if (!av.getWrapAlignment())
1131 drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq,
1136 drawWrappedSelection(g, group, getWidth(), getHeight(),
1137 av.getRanges().getStartRes());
1141 return selectionImage;
1145 * Draw a selection group over an unwrapped alignment
1146 * @param g graphics object to draw with
1147 * @param group selection group
1148 * @param startRes start residue of area to draw
1149 * @param endRes end residue of area to draw
1150 * @param startSeq start sequence of area to draw
1151 * @param endSeq end sequence of area to draw
1152 * @param offset vertical offset (used when called from wrapped alignment code)
1154 private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group,
1155 int startRes, int endRes, int startSeq, int endSeq, int offset)
1157 if (!av.hasHiddenColumns())
1159 drawSelectionGroupPart(g, group, startRes, endRes, startSeq, endSeq,
1164 // package into blocks of visible columns
1166 int blockStart = startRes;
1167 int blockEnd = endRes;
1169 for (int[] region : av.getAlignment().getHiddenColumns()
1170 .getHiddenColumnsCopy())
1172 int hideStart = region[0];
1173 int hideEnd = region[1];
1175 if (hideStart <= blockStart)
1177 blockStart += (hideEnd - hideStart) + 1;
1181 blockEnd = hideStart - 1;
1183 g.translate(screenY * charWidth, 0);
1184 drawSelectionGroupPart(g, group,
1185 blockStart, blockEnd, startSeq, endSeq, offset);
1187 g.translate(-screenY * charWidth, 0);
1188 screenY += blockEnd - blockStart + 1;
1189 blockStart = hideEnd + 1;
1191 if (screenY > (endRes - startRes))
1193 // already rendered last block
1198 if (screenY <= (endRes - startRes))
1200 // remaining visible region to render
1201 blockEnd = blockStart + (endRes - startRes) - screenY;
1202 g.translate(screenY * charWidth, 0);
1203 drawSelectionGroupPart(g, group,
1204 blockStart, blockEnd, startSeq, endSeq, offset);
1206 g.translate(-screenY * charWidth, 0);
1212 * Draw the selection group as a separate image and overlay
1214 private void drawSelectionGroupPart(Graphics2D g, SequenceGroup group,
1215 int startRes, int endRes, int startSeq, int endSeq,
1218 int visWidth = (endRes - startRes + 1) * charWidth;
1222 boolean inGroup = false;
1230 for (i = startSeq; i <= endSeq; i++)
1232 // position of start residue of group relative to startRes, in pixels
1233 sx = (group.getStartRes() - startRes) * charWidth;
1235 // width of group in pixels
1236 xwidth = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
1239 sy = verticalOffset + (i - startSeq) * charHeight;
1241 if (sx + xwidth < 0 || sx > visWidth)
1246 if ((sx <= (endRes - startRes) * charWidth)
1247 && group.getSequences(null)
1248 .contains(av.getAlignment().getSequenceAt(i)))
1250 if ((bottom == -1) && !group.getSequences(null)
1251 .contains(av.getAlignment().getSequenceAt(i + 1)))
1253 bottom = sy + charHeight;
1258 if (((top == -1) && (i == 0)) || !group.getSequences(null)
1259 .contains(av.getAlignment().getSequenceAt(i - 1)))
1272 // if start position is visible, draw vertical line to left of
1274 if (sx >= 0 && sx < visWidth)
1276 g.drawLine(sx, oldY, sx, sy);
1279 // if end position is visible, draw vertical line to right of
1281 if (sx + xwidth < visWidth)
1283 g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
1292 if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
1294 xwidth = (endRes - startRes + 1) * charWidth - sx;
1297 // draw horizontal line at top of group
1300 g.drawLine(sx, top, sx + xwidth, top);
1304 // draw horizontal line at bottom of group
1307 g.drawLine(sx, bottom, sx + xwidth, bottom);
1318 sy = verticalOffset + ((i - startSeq) * charHeight);
1319 if (sx >= 0 && sx < visWidth)
1321 g.drawLine(sx, oldY, sx, sy);
1324 if (sx + xwidth < visWidth)
1326 g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
1335 if (sx + xwidth > visWidth)
1339 else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
1341 xwidth = (endRes - startRes + 1) * charWidth;
1346 g.drawLine(sx, top, sx + xwidth, top);
1352 g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
1366 public void highlightSearchResults(SearchResultsI results)
1370 av.setSearchResults(results);
1376 public void propertyChange(PropertyChangeEvent evt)
1378 String eventName = evt.getPropertyName();
1380 if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
1384 else if (av.getWrapAlignment())
1386 if (eventName.equals(ViewportRanges.STARTRES))
1394 if (eventName.equals(ViewportRanges.STARTRES))
1396 // Make sure we're not trying to draw a panel
1397 // larger than the visible window
1398 ViewportRanges vpRanges = av.getRanges();
1399 scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
1400 int range = vpRanges.getEndRes() - vpRanges.getStartRes();
1401 if (scrollX > range)
1405 else if (scrollX < -range)
1411 // Both scrolling and resizing change viewport ranges: scrolling changes
1412 // both start and end points, but resize only changes end values.
1413 // Here we only want to fastpaint on a scroll, with resize using a normal
1414 // paint, so scroll events are identified as changes to the horizontal or
1415 // vertical start value.
1416 if (eventName.equals(ViewportRanges.STARTRES))
1418 // scroll - startres and endres both change
1419 fastPaint(scrollX, 0);
1421 else if (eventName.equals(ViewportRanges.STARTSEQ))
1424 fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());