From: gmungoc Date: Tue, 27 Jun 2017 13:01:47 +0000 (+0100) Subject: JAL-1858 highlights on wrapped panel - work in progress X-Git-Tag: Release_2_10_3b1~186 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=d346ed81a91c4fbed1836379bb794ed908cd9a11;p=jalview.git JAL-1858 highlights on wrapped panel - work in progress --- diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 8707e9a..ed3d298 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -52,6 +52,8 @@ import javax.swing.JComponent; */ public class SeqCanvas extends JComponent implements ViewportListenerI { + private static String ZEROS = "0000000000"; + final FeatureRenderer fr; final SequenceRenderer sr; @@ -68,9 +70,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI boolean fastPaint = false; - int LABEL_WEST; + int labelWidthWest; - int LABEL_EAST; + int labelWidthEast; int cursorX = 0; @@ -206,7 +208,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (value != -1) { - int x = LABEL_WEST - fm.stringWidth(String.valueOf(value)) + int x = labelWidthWest - fm.stringWidth(String.valueOf(value)) - charWidth / 2; g.drawString(value + "", x, (ypos + (i * charHeight)) - (charHeight / 5)); @@ -422,46 +424,46 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { FontMetrics fm = getFontMetrics(av.getFont()); - LABEL_EAST = 0; - LABEL_WEST = 0; + labelWidthEast = 0; + labelWidthWest = 0; if (av.getScaleRightWrapped()) { - LABEL_EAST = fm.stringWidth(getMask()); + labelWidthEast = getLabelWidth(fm); } if (av.getScaleLeftWrapped()) { - LABEL_WEST = fm.stringWidth(getMask()); + labelWidthWest = getLabelWidth(fm); } - return (cwidth - LABEL_EAST - LABEL_WEST) / charWidth; + return (cwidth - labelWidthEast - labelWidthWest) / charWidth; } /** - * Generates a string of zeroes. + * Returns a pixel width suitable for showing the largest sequence coordinate + * (end position) in the alignment. Returns 2 plus the number of decimal + * digits to be shown (3 for 1-10, 4 for 11-99 etc). * - * @return String + * @param fm + * @return */ - String getMask() + protected int getLabelWidth(FontMetrics fm) { - String mask = "00"; int maxWidth = 0; - int tmp; for (int i = 0; i < av.getAlignment().getHeight(); i++) { - tmp = av.getAlignment().getSequenceAt(i).getEnd(); - if (tmp > maxWidth) - { - maxWidth = tmp; - } + maxWidth = Math.max(maxWidth, av.getAlignment().getSequenceAt(i) + .getEnd()); } + int length = 2; for (int i = maxWidth; i > 0; i /= 10) { - mask += "0"; + length++; } - return mask; + + return fm.stringWidth(ZEROS.substring(0, length)); } /** @@ -482,17 +484,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI updateViewport(); AlignmentI al = av.getAlignment(); - FontMetrics fm = getFontMetrics(av.getFont()); - - if (av.getScaleRightWrapped()) + int labelWidth = 0; + if (av.getScaleRightWrapped() || av.getScaleLeftWrapped()) { - LABEL_EAST = fm.stringWidth(getMask()); + FontMetrics fm = getFontMetrics(av.getFont()); + labelWidth = getLabelWidth(fm); } - if (av.getScaleLeftWrapped()) - { - LABEL_WEST = fm.stringWidth(getMask()); - } + labelWidthEast = av.getScaleRightWrapped() ? labelWidth : 0; + labelWidthWest = av.getScaleLeftWrapped() ? labelWidth : 0; int hgap = charHeight; if (av.getScaleAboveWrapped()) @@ -500,7 +500,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI hgap += charHeight; } - int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / charWidth; + int cWidth = (canvasWidth - labelWidthEast - labelWidthWest) / charWidth; int cHeight = av.getAlignment().getHeight() * charHeight; av.setWrappedWidth(cWidth); @@ -517,6 +517,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI .findColumnPosition(maxwidth) - 1; } + int annotationHeight = getAnnotationHeight(); + while ((ypos <= canvasHeight) && (startRes < maxwidth)) { endx = startRes + cWidth - 1; @@ -536,12 +538,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.getScaleRightWrapped()) { - g.translate(canvasWidth - LABEL_EAST, 0); + g.translate(canvasWidth - labelWidthEast, 0); drawEastScale(g, startRes, endx, ypos); - g.translate(-(canvasWidth - LABEL_EAST), 0); + g.translate(-(canvasWidth - labelWidthEast), 0); } - g.translate(LABEL_WEST, 0); + g.translate(labelWidthWest, 0); if (av.getScaleAboveWrapped()) { @@ -601,9 +603,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.translate(0, -cHeight - ypos - 3); } g.setClip(clip); - g.translate(-LABEL_WEST, 0); + g.translate(-labelWidthWest, 0); - ypos += cHeight + getAnnotationHeight() + hgap; + ypos += cHeight + annotationHeight + hgap; startRes += cWidth; } @@ -989,23 +991,28 @@ public class SeqCanvas extends JComponent implements ViewportListenerI /** * Highlights search results in the visible region by rendering as white text - * on a black background. Any previous highlighting is removed. + * on a black background. Any previous highlighting is removed. Answers true + * if any highlight was left on the visible alignment (so status bar should be + * set to match), else false. * * @param results + * @return */ - public void highlightSearchResults(SearchResultsI results) + public boolean highlightSearchResults(SearchResultsI results) { updateViewport(); /* * for now, don't attempt fastpaint if wrapped format */ - if (av.getWrapAlignment()) + boolean wrapped = av.getWrapAlignment(); + if (wrapped) { - img = null; - av.setSearchResults(results); - repaint(); - return; + // drawWrappedMappedPositions(results); + // img = null; + // av.setSearchResults(results); + // repaint(); + // return; } fastpainting = true; @@ -1020,16 +1027,39 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ SearchResultsI previous = av.getSearchResults(); av.setSearchResults(results); - boolean redrawn = drawMappedPositions(previous); - redrawn |= drawMappedPositions(results); + boolean redrawn = false; + boolean drawn = false; + if (wrapped) + { + redrawn = drawWrappedMappedPositions(previous); + drawn = drawWrappedMappedPositions(results); + redrawn |= drawn; + } + else + { + redrawn = drawMappedPositions(previous); + drawn = drawMappedPositions(results); + redrawn |= drawn; + } + + /* + * if highlights were either removed or added, repaint + */ if (redrawn) { repaint(); } + + /* + * return true only if highlights were added + */ + return drawn; + } finally { fastpainting = false; } + } /** @@ -1154,4 +1184,123 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } } + + /** + * Redraws any positions in the search results in the visible region. Any + * highlights are drawn depending on the search results set on the Viewport, + * not the results parameter. This allows this method to be called to either + * clear highlighting (passing the previous search results), or set new + * highlighting. + * + * @param results + * @return + */ + protected boolean drawWrappedMappedPositions(SearchResultsI results) + { + if (results == null) + { + return false; + } + + boolean matchFound = false; + + /* + * Viewport ranges are set for the 'row' of the wrapped alignment + * the cursor is in, not the whole visible region; really we want + * the latter; +-6 a temporary fudge for codons wrapping across lines + */ + ViewportRanges ranges = av.getRanges(); + int firstVisibleColumn = ranges.getStartRes() - 6; + int lastVisibleColumn = ranges.getEndRes() + 6; + AlignmentI alignment = av.getAlignment(); + if (av.hasHiddenColumns()) + { + firstVisibleColumn = alignment.getHiddenColumns() + .adjustForHiddenColumns(firstVisibleColumn); + lastVisibleColumn = alignment.getHiddenColumns() + .adjustForHiddenColumns(lastVisibleColumn); + } + + /* + * find width of alignment in residues, and height of alignment, + * so we can calculate where to render each matched position + */ + int wrappedWidth = av.getWrappedWidth(); + int wrappedHeight = av.getAlignment().getHeight() * av.getCharHeight(); + int gapHeight = av.getCharHeight() + * (av.getScaleAboveWrapped() ? 2 : 1); + wrappedHeight += gapHeight; + wrappedHeight += getAnnotationHeight(); + + for (int seqNo = ranges.getStartSeq(); seqNo <= ranges + .getEndSeq(); seqNo++) + { + SequenceI seq = alignment.getSequenceAt(seqNo); + + int[] visibleResults = results.getResults(seq, firstVisibleColumn, + lastVisibleColumn); + if (visibleResults != null) + { + for (int i = 0; i < visibleResults.length - 1; i += 2) + { + int firstMatchedColumn = visibleResults[i]; + int lastMatchedColumn = visibleResults[i + 1]; + if (firstMatchedColumn <= lastVisibleColumn + && lastMatchedColumn >= firstVisibleColumn) + { + /* + * found a search results match in the visible region + */ + firstMatchedColumn = Math.max(firstMatchedColumn, + firstVisibleColumn); + lastMatchedColumn = Math.min(lastMatchedColumn, + lastVisibleColumn); + + /* + * draw each mapped position separately (as contiguous positions may + * wrap across lines) + */ + for (int mappedPos = firstMatchedColumn; mappedPos <= lastMatchedColumn; mappedPos++) + { + int displayColumn = mappedPos; + if (av.hasHiddenColumns()) + { + displayColumn = alignment.getHiddenColumns() + .findColumnPosition(displayColumn); + } + + /* + * transX: offset from left edge of canvas to residue position + */ + int transX = labelWidthWest + + ((displayColumn - ranges.getStartRes()) % wrappedWidth) + * av.getCharWidth(); + + /* + * transY: offset from top edge of canvas to residue position + */ + int transY = gapHeight; + transY += (displayColumn / wrappedWidth) * wrappedHeight; + transY += (seqNo - ranges.getStartSeq()) * av.getCharHeight(); + + /* + * yOffset is from graphics origin to start of visible region + */ + int yOffset = 0;// (displayColumn / wrappedWidth) * wrappedHeight; + if (transY < getHeight()) + { + matchFound = true; + gg.translate(transX, transY); + drawPanel(gg, displayColumn, displayColumn, seqNo, seqNo, + yOffset); + gg.translate(-transX, -transY); + } + } + } + } + } + } + + return matchFound; + } } diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 5634ead..55a508b 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -215,7 +215,7 @@ public class SeqPanel extends JPanel implements MouseListener, int y = evt.getY(); y -= hgap; - x -= seqCanvas.LABEL_WEST; + x -= seqCanvas.labelWidthWest; int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth()); if (cwidth < 1) @@ -694,8 +694,10 @@ public class SeqPanel extends JPanel implements MouseListener, } ap.setToScrollComplementPanel(true); } - setStatusMessage(results); - seqCanvas.highlightSearchResults(results); + if (seqCanvas.highlightSearchResults(results)) + { + setStatusMessage(results); + } } @Override