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;
82 AnnotationPanel annotations;
85 * Creates a new SeqCanvas object.
90 public SeqCanvas(AlignmentPanel ap)
94 fr = new FeatureRenderer(ap);
95 seqRdr = new SequenceRenderer(av);
96 setLayout(new BorderLayout());
97 PaintRefresher.Register(this, av.getSequenceSetId());
98 setBackground(Color.white);
100 av.getRanges().addPropertyChangeListener(this);
103 public SequenceRenderer getSequenceRenderer()
108 public FeatureRenderer getFeatureRenderer()
113 private void updateViewport()
115 charHeight = av.getCharHeight();
116 charWidth = av.getCharWidth();
131 private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
134 for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx,
137 int mpos = mark.column; // (i - startx - 1)
142 String mstring = mark.text;
148 g.drawString(mstring, mpos * charWidth, ypos - (charHeight / 2));
150 g.drawLine((mpos * charWidth) + (charWidth / 2), (ypos + 2)
151 - (charHeight / 2), (mpos * charWidth) + (charWidth / 2),
169 void drawWestScale(Graphics g, int startx, int endx, int ypos)
171 FontMetrics fm = getFontMetrics(av.getFont());
174 if (av.hasHiddenColumns())
176 startx = av.getAlignment().getHiddenColumns()
177 .adjustForHiddenColumns(startx);
178 endx = av.getAlignment().getHiddenColumns()
179 .adjustForHiddenColumns(endx);
182 int maxwidth = av.getAlignment().getWidth();
183 if (av.hasHiddenColumns())
185 maxwidth = av.getAlignment().getHiddenColumns()
186 .findColumnPosition(maxwidth) - 1;
190 for (int i = 0; i < av.getAlignment().getHeight(); i++)
192 SequenceI seq = av.getAlignment().getSequenceAt(i);
198 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
205 value = av.getAlignment().getSequenceAt(i).findPosition(index);
212 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))
214 g.drawString(value + "", x, (ypos + (i * charHeight))
232 void drawEastScale(Graphics g, int startx, int endx, int ypos)
236 if (av.hasHiddenColumns())
238 endx = av.getAlignment().getHiddenColumns()
239 .adjustForHiddenColumns(endx);
244 for (int i = 0; i < av.getAlignment().getHeight(); i++)
246 seq = av.getAlignment().getSequenceAt(i);
250 while (index > startx)
252 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
259 value = seq.findPosition(index);
266 g.drawString(String.valueOf(value), 0, (ypos + (i * charHeight))
274 * need to make this thread safe move alignment rendering in response to
280 * shift up or down in repaint
282 public void fastPaint(int horizontal, int vertical)
284 if (fastpainting || gg == null)
292 ViewportRanges ranges = av.getRanges();
293 int sr = ranges.getStartRes();
294 int er = ranges.getEndRes();
295 int ss = ranges.getStartSeq();
296 int es = ranges.getEndSeq();
300 gg.copyArea(horizontal * charWidth, vertical * charHeight,
301 img.getWidth(), img.getHeight(), -horizontal * charWidth,
302 -vertical * charHeight);
304 if (horizontal > 0) // scrollbar pulled right, image to the left
306 transX = (er - sr - horizontal) * charWidth;
307 sr = er - horizontal;
309 else if (horizontal < 0)
311 er = sr - horizontal;
313 else if (vertical > 0) // scroll down
317 if (ss < ranges.getStartSeq())
318 { // ie scrolling too fast, more than a page at a time
319 ss = ranges.getStartSeq();
323 transY = img.getHeight() - ((vertical + 1) * charHeight);
326 else if (vertical < 0)
330 if (es > ranges.getEndSeq())
332 es = ranges.getEndSeq();
336 gg.translate(transX, transY);
337 drawPanel(gg, sr, er, ss, es, 0);
338 gg.translate(-transX, -transY);
341 fastpainting = false;
345 * Definitions of startx and endx (hopefully): SMJS This is what I'm working
346 * towards! startx is the first residue (starting at 0) to display. endx is
347 * the last residue to display (starting at 0). starty is the first sequence
348 * to display (starting at 0). endy is the last sequence to display (starting
349 * at 0). NOTE 1: The av limits are set in setFont in this class and in the
350 * adjustment listener in SeqPanel when the scrollbars move.
353 // Set this to false to force a full panel paint
355 public void paintComponent(Graphics g)
357 super.paintComponent(g);
361 ViewportRanges ranges = av.getRanges();
363 int width = getWidth();
364 int height = getHeight();
366 width -= (width % charWidth);
367 height -= (height % charHeight);
369 // selectImage is the selection group outline image
370 BufferedImage selectImage = drawSelectionGroup(
371 ranges.getStartRes(), ranges.getEndRes(),
372 ranges.getStartSeq(), ranges.getEndSeq());
374 if (fastPaint || (getVisibleRect().width != g.getClipBounds().width)
375 || (getVisibleRect().height != g.getClipBounds().height))
377 BufferedImage lcimg = buildLocalImage(selectImage);
378 g.drawImage(lcimg, 0, 0, this);
381 else if ((width > 0) && (height > 0))
383 // img is a cached version of the last view we drew, if any
384 // if we have no img or the size has changed, make a new one
385 if (img == null || width != img.getWidth()
386 || height != img.getHeight())
393 gg = (Graphics2D) img.getGraphics();
394 gg.setFont(av.getFont());
399 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
400 RenderingHints.VALUE_ANTIALIAS_ON);
403 gg.setColor(Color.white);
404 gg.fillRect(0, 0, img.getWidth(), img.getHeight());
406 if (av.getWrapAlignment())
408 drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
412 drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
413 ranges.getStartSeq(), ranges.getEndSeq(), 0);
416 // lcimg is a local *copy* of img which we'll draw selectImage on top of
417 BufferedImage lcimg = buildLocalImage(selectImage);
418 g.drawImage(lcimg, 0, 0, this);
423 * Make a local image by combining the cached image img
426 private BufferedImage buildLocalImage(BufferedImage selectImage)
428 // clone the cached image
429 BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(),
431 Graphics2D g2d = lcimg.createGraphics();
432 g2d.drawImage(img, 0, 0, null);
434 // overlay selection group on lcimg
435 if (selectImage != null)
438 AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
439 g2d.drawImage(selectImage, 0, 0, this);
447 * Set up a buffered image of the correct height and size for the sequence canvas
449 private BufferedImage setupImage()
451 BufferedImage lcimg = null;
453 int width = getWidth();
454 int height = getHeight();
456 width -= (width % charWidth);
457 height -= (height % charHeight);
459 if ((width < 1) || (height < 1))
466 lcimg = new BufferedImage(width, height,
467 BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
468 } catch (OutOfMemoryError er)
472 "Group image OutOfMemory Redraw Error.\n" + er);
473 new OOMWarning("Creating alignment image for display", er);
487 * @return DOCUMENT ME!
489 public int getWrappedCanvasWidth(int cwidth)
491 FontMetrics fm = getFontMetrics(av.getFont());
496 if (av.getScaleRightWrapped())
498 LABEL_EAST = fm.stringWidth(getMask());
501 if (av.getScaleLeftWrapped())
503 LABEL_WEST = fm.stringWidth(getMask());
506 return (cwidth - LABEL_EAST - LABEL_WEST) / charWidth;
510 * Generates a string of zeroes.
519 for (int i = 0; i < av.getAlignment().getHeight(); i++)
521 tmp = av.getAlignment().getSequenceAt(i).getEnd();
528 for (int i = maxWidth; i > 0; i /= 10)
542 * @param canvasHeight
547 public void drawWrappedPanel(Graphics g, int canvasWidth,
548 int canvasHeight, int startRes)
551 AlignmentI al = av.getAlignment();
553 FontMetrics fm = getFontMetrics(av.getFont());
558 if (av.getScaleRightWrapped())
560 LABEL_EAST = fm.stringWidth(getMask());
563 if (av.getScaleLeftWrapped())
565 LABEL_WEST = fm.stringWidth(getMask());
568 int hgap = charHeight;
569 if (av.getScaleAboveWrapped())
574 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth;
575 int cHeight = av.getAlignment().getHeight() * charHeight;
577 av.setWrappedWidth(cWidth);
579 av.getRanges().setViewportStartAndWidth(startRes, cWidth);
583 int maxwidth = av.getAlignment().getWidth();
585 if (av.hasHiddenColumns())
587 maxwidth = av.getAlignment().getHiddenColumns()
588 .findColumnPosition(maxwidth);
591 while ((ypos <= canvasHeight) && (startRes < maxwidth))
593 endx = startRes + cWidth - 1;
600 g.setFont(av.getFont());
601 g.setColor(Color.black);
603 if (av.getScaleLeftWrapped())
605 drawWestScale(g, startRes, endx, ypos);
608 if (av.getScaleRightWrapped())
610 g.translate(canvasWidth - LABEL_EAST, 0);
611 drawEastScale(g, startRes, endx, ypos);
612 g.translate(-(canvasWidth - LABEL_EAST), 0);
615 g.translate(LABEL_WEST, 0);
617 if (av.getScaleAboveWrapped())
619 drawNorthScale(g, startRes, endx, ypos);
622 if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
624 g.setColor(Color.blue);
626 HiddenColumns hidden = av.getAlignment().getHiddenColumns();
627 List<Integer> positions = hidden.findHiddenRegionPositions();
628 for (int pos : positions)
630 res = pos - startRes;
632 if (res < 0 || res > endx - startRes)
638 new int[] { res * charWidth - charHeight / 4,
639 res * charWidth + charHeight / 4, res * charWidth },
640 new int[] { ypos - (charHeight / 2),
641 ypos - (charHeight / 2), ypos - (charHeight / 2) + 8 },
647 // When printing we have an extra clipped region,
648 // the Printable page which we need to account for here
649 Shape clip = g.getClip();
653 g.setClip(0, 0, cWidth * charWidth, canvasHeight);
657 g.setClip(0, (int) clip.getBounds().getY(), cWidth * charWidth,
658 (int) clip.getBounds().getHeight());
661 drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
663 if (av.isShowAnnotation())
665 g.translate(0, cHeight + ypos + 3);
666 if (annotations == null)
668 annotations = new AnnotationPanel(av);
671 annotations.renderer.drawComponent(annotations, av, g, -1,
673 g.translate(0, -cHeight - ypos - 3);
676 g.translate(-LABEL_WEST, 0);
678 ypos += cHeight + getAnnotationHeight() + hgap;
685 * Draw a selection group over a wrapped alignment
687 private void drawWrappedSelection(Graphics2D g, SequenceGroup group,
689 int canvasHeight, int startRes)
691 // height gap above each panel
692 int hgap = charHeight;
693 if (av.getScaleAboveWrapped())
698 int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth;
699 int cHeight = av.getAlignment().getHeight() * charHeight;
701 int startx = startRes;
703 int ypos = hgap; // vertical offset
704 int maxwidth = av.getAlignment().getWidth();
706 if (av.hasHiddenColumns())
708 maxwidth = av.getAlignment().getHiddenColumns()
709 .findColumnPosition(maxwidth);
712 // chop the wrapped alignment extent up into panel-sized blocks and treat
713 // each block as if it were a block from an unwrapped alignment
714 while ((ypos <= canvasHeight) && (startx < maxwidth))
716 // set end value to be start + width, or maxwidth, whichever is smaller
717 endx = startx + cWidth - 1;
724 g.translate(LABEL_WEST, 0);
726 drawUnwrappedSelection(g, group, startx, endx, 0,
727 av.getAlignment().getHeight() - 1,
730 g.translate(-LABEL_WEST, 0);
732 // update vertical offset
733 ypos += cHeight + getAnnotationHeight() + hgap;
735 // update horizontal offset
740 int getAnnotationHeight()
742 if (!av.isShowAnnotation())
747 if (annotations == null)
749 annotations = new AnnotationPanel(av);
752 return annotations.adjustPanelHeight();
771 public void drawPanel(Graphics g1, int startRes, int endRes,
772 int startSeq, int endSeq, int offset)
775 if (!av.hasHiddenColumns())
777 draw(g1, startRes, endRes, startSeq, endSeq, offset);
782 int blockStart = startRes;
783 int blockEnd = endRes;
785 for (int[] region : av.getAlignment().getHiddenColumns()
786 .getHiddenColumnsCopy())
788 int hideStart = region[0];
789 int hideEnd = region[1];
791 if (hideStart <= blockStart)
793 blockStart += (hideEnd - hideStart) + 1;
797 blockEnd = hideStart - 1;
799 g1.translate(screenY * charWidth, 0);
801 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
803 if (av.getShowHiddenMarkers())
805 g1.setColor(Color.blue);
807 g1.drawLine((blockEnd - blockStart + 1) * charWidth - 1,
808 0 + offset, (blockEnd - blockStart + 1) * charWidth - 1,
809 (endSeq - startSeq + 1) * charHeight + offset);
812 g1.translate(-screenY * charWidth, 0);
813 screenY += blockEnd - blockStart + 1;
814 blockStart = hideEnd + 1;
816 if (screenY > (endRes - startRes))
818 // already rendered last block
823 if (screenY <= (endRes - startRes))
825 // remaining visible region to render
826 blockEnd = blockStart + (endRes - startRes) - screenY;
827 g1.translate(screenY * charWidth, 0);
828 draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
830 g1.translate(-screenY * charWidth, 0);
836 private void draw(Graphics g, int startRes, int endRes, int startSeq,
837 int endSeq, int offset)
839 g.setFont(av.getFont());
840 seqRdr.prepare(g, av.isRenderGaps());
844 // / First draw the sequences
845 // ///////////////////////////
846 for (int i = startSeq; i <= endSeq; i++)
848 nextSeq = av.getAlignment().getSequenceAt(i);
851 // occasionally, a race condition occurs such that the alignment row is
855 seqRdr.drawSequence(nextSeq, av.getAlignment().findAllGroups(nextSeq),
856 startRes, endRes, offset + ((i - startSeq) * charHeight));
858 if (av.isShowSequenceFeatures())
860 fr.drawSequence(g, nextSeq, startRes, endRes, offset
861 + ((i - startSeq) * charHeight), false);
864 // / Highlight search Results once all sequences have been drawn
865 // ////////////////////////////////////////////////////////
866 if (av.hasSearchResults())
868 int[] visibleResults = av.getSearchResults().getResults(nextSeq,
870 if (visibleResults != null)
872 for (int r = 0; r < visibleResults.length; r += 2)
874 seqRdr.drawHighlightedText(nextSeq, visibleResults[r],
875 visibleResults[r + 1], (visibleResults[r] - startRes)
877 + ((i - startSeq) * charHeight));
882 if (av.cursorMode && cursorY == i && cursorX >= startRes
883 && cursorX <= endRes)
885 seqRdr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
886 offset + ((i - startSeq) * charHeight));
890 if (av.getSelectionGroup() != null
891 || av.getAlignment().getGroups().size() > 0)
893 drawGroupsBoundaries(g, startRes, endRes, startSeq, endSeq, offset);
898 void drawGroupsBoundaries(Graphics g1, int startRes, int endRes,
899 int startSeq, int endSeq, int offset)
901 Graphics2D g = (Graphics2D) g1;
903 // ///////////////////////////////////
904 // Now outline any areas if necessary
905 // ///////////////////////////////////
907 SequenceGroup group = null;
910 if (av.getAlignment().getGroups().size() > 0)
912 group = av.getAlignment().getGroups().get(0);
918 g.setStroke(new BasicStroke());
919 g.setColor(group.getOutlineColour());
923 drawPartialGroupOutline(g, group, startRes, endRes, startSeq,
928 g.setStroke(new BasicStroke());
930 if (groupIndex >= av.getAlignment().getGroups().size())
935 group = av.getAlignment().getGroups().get(groupIndex);
937 } while (groupIndex < av.getAlignment().getGroups().size());
945 * Draw the selection group as a separate image and overlay
947 private BufferedImage drawSelectionGroup(int startRes, int endRes,
948 int startSeq, int endSeq)
950 // get a new image of the correct size
951 BufferedImage selectionImage = setupImage();
953 if (selectionImage == null)
958 SequenceGroup group = av.getSelectionGroup();
965 // set up drawing colour
966 Graphics2D g = (Graphics2D) selectionImage.getGraphics();
968 // set background to transparent
969 g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
970 g.fillRect(0, 0, selectionImage.getWidth(), selectionImage.getHeight());
972 // set up foreground to draw red dashed line
973 g.setComposite(AlphaComposite.Src);
974 g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
975 BasicStroke.JOIN_ROUND, 3f, new float[]
977 g.setColor(Color.RED);
979 if (!av.getWrapAlignment())
981 drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq,
986 drawWrappedSelection(g, group, getWidth(), getHeight(),
987 av.getRanges().getStartRes());
991 return selectionImage;
995 * Draw a selection group over an unwrapped alignment
996 * @param g graphics object to draw with
997 * @param group selection group
998 * @param startRes start residue of area to draw
999 * @param endRes end residue of area to draw
1000 * @param startSeq start sequence of area to draw
1001 * @param endSeq end sequence of area to draw
1002 * @param offset vertical offset (used when called from wrapped alignment code)
1004 private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group,
1005 int startRes, int endRes, int startSeq, int endSeq, int offset)
1007 if (!av.hasHiddenColumns())
1009 drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq,
1014 // package into blocks of visible columns
1016 int blockStart = startRes;
1017 int blockEnd = endRes;
1019 for (int[] region : av.getAlignment().getHiddenColumns()
1020 .getHiddenColumnsCopy())
1022 int hideStart = region[0];
1023 int hideEnd = region[1];
1025 if (hideStart <= blockStart)
1027 blockStart += (hideEnd - hideStart) + 1;
1031 blockEnd = hideStart - 1;
1033 g.translate(screenY * charWidth, 0);
1034 drawPartialGroupOutline(g, group,
1035 blockStart, blockEnd, startSeq, endSeq, offset);
1037 g.translate(-screenY * charWidth, 0);
1038 screenY += blockEnd - blockStart + 1;
1039 blockStart = hideEnd + 1;
1041 if (screenY > (endRes - startRes))
1043 // already rendered last block
1048 if (screenY <= (endRes - startRes))
1050 // remaining visible region to render
1051 blockEnd = blockStart + (endRes - startRes) - screenY;
1052 g.translate(screenY * charWidth, 0);
1053 drawPartialGroupOutline(g, group,
1054 blockStart, blockEnd, startSeq, endSeq, offset);
1056 g.translate(-screenY * charWidth, 0);
1062 * Draw the selection group as a separate image and overlay
1064 private void drawPartialGroupOutline(Graphics2D g, SequenceGroup group,
1065 int startRes, int endRes, int startSeq, int endSeq,
1068 int visWidth = (endRes - startRes + 1) * charWidth;
1072 boolean inGroup = false;
1080 for (i = startSeq; i <= endSeq; i++)
1082 // position of start residue of group relative to startRes, in pixels
1083 sx = (group.getStartRes() - startRes) * charWidth;
1085 // width of group in pixels
1086 xwidth = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
1089 sy = verticalOffset + (i - startSeq) * charHeight;
1091 if (sx + xwidth < 0 || sx > visWidth)
1096 if ((sx <= (endRes - startRes) * charWidth)
1097 && group.getSequences(null)
1098 .contains(av.getAlignment().getSequenceAt(i)))
1100 if ((bottom == -1) && !group.getSequences(null)
1101 .contains(av.getAlignment().getSequenceAt(i + 1)))
1103 bottom = sy + charHeight;
1108 if (((top == -1) && (i == 0)) || !group.getSequences(null)
1109 .contains(av.getAlignment().getSequenceAt(i - 1)))
1122 // if start position is visible, draw vertical line to left of
1124 if (sx >= 0 && sx < visWidth)
1126 g.drawLine(sx, oldY, sx, sy);
1129 // if end position is visible, draw vertical line to right of
1131 if (sx + xwidth < visWidth)
1133 g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
1142 // don't let width extend beyond current block, or group extent
1144 if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
1146 xwidth = (endRes - startRes + 1) * charWidth - sx;
1149 // draw horizontal line at top of group
1152 g.drawLine(sx, top, sx + xwidth, top);
1156 // draw horizontal line at bottom of group
1159 g.drawLine(sx, bottom, sx + xwidth, bottom);
1170 sy = verticalOffset + ((i - startSeq) * charHeight);
1171 if (sx >= 0 && sx < visWidth)
1173 g.drawLine(sx, oldY, sx, sy);
1176 if (sx + xwidth < visWidth)
1178 g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
1187 if (sx + xwidth > visWidth)
1191 else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
1193 xwidth = (endRes - startRes + 1) * charWidth;
1198 g.drawLine(sx, top, sx + xwidth, top);
1204 g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
1218 public void highlightSearchResults(SearchResultsI results)
1222 av.setSearchResults(results);
1228 public void propertyChange(PropertyChangeEvent evt)
1230 String eventName = evt.getPropertyName();
1232 if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
1237 else if (av.getWrapAlignment())
1239 if (eventName.equals(ViewportRanges.STARTRES))
1247 if (eventName.equals(ViewportRanges.STARTRES))
1249 // Make sure we're not trying to draw a panel
1250 // larger than the visible window
1251 ViewportRanges vpRanges = av.getRanges();
1252 scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
1253 int range = vpRanges.getEndRes() - vpRanges.getStartRes();
1254 if (scrollX > range)
1258 else if (scrollX < -range)
1264 // Both scrolling and resizing change viewport ranges: scrolling changes
1265 // both start and end points, but resize only changes end values.
1266 // Here we only want to fastpaint on a scroll, with resize using a normal
1267 // paint, so scroll events are identified as changes to the horizontal or
1268 // vertical start value.
1269 if (eventName.equals(ViewportRanges.STARTRES))
1271 // scroll - startres and endres both change
1272 fastPaint(scrollX, 0);
1274 else if (eventName.equals(ViewportRanges.STARTSEQ))
1277 fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());