From 518c10ed28fbc64c637bbe1a0f336d8e3bf594a6 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Wed, 3 Oct 2018 13:53:25 +0100 Subject: [PATCH] JAL-3093 tweaks to code and test for 3px gap above annotations in wrapped mode --- src/jalview/gui/SeqCanvas.java | 32 +++++++----- src/jalview/gui/SeqPanel.java | 73 ++++++++++++++++++---------- test/jalview/gui/SeqCanvasTest.java | 30 ++++++------ test/jalview/gui/SeqPanelTest.java | 91 ++++++++++++++++++++++++++++++++++- 4 files changed, 173 insertions(+), 53 deletions(-) diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 31c8a47..dc87eba 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -87,9 +87,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private int labelWidthWest; // label left width in pixels if shown - private int wrappedSpaceAboveAlignment; // gap between widths + int wrappedSpaceAboveAlignment; // gap between widths - private int wrappedRepeatHeightPx; // height in pixels of wrapped width + int wrappedRepeatHeightPx; // height in pixels of wrapped width private int wrappedVisibleWidths; // number of wrapped widths displayed @@ -564,7 +564,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI calculateWrappedGeometry(canvasWidth, canvasHeight); /* - * draw one width at a time (excluding any scales or annotation shown), + * draw one width at a time (excluding any scales shown), * until we have run out of either alignment or vertical space available */ int ypos = wrappedSpaceAboveAlignment; @@ -611,14 +611,22 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * (av.getScaleAboveWrapped() ? 2 : 1); /* - * height in pixels of the wrapped widths + * compute height in pixels of the wrapped widths + * - start with space above plus sequences */ wrappedRepeatHeightPx = wrappedSpaceAboveAlignment; - // add sequences wrappedRepeatHeightPx += av.getAlignment().getHeight() * charHeight; - // add annotations panel height if shown - wrappedRepeatHeightPx += getAnnotationHeight(); + + /* + * add annotations panel height if shown + * also gap between sequences and annotations + */ + if (av.isShowAnnotation()) + { + wrappedRepeatHeightPx += getAnnotationHeight(); + wrappedRepeatHeightPx += SEQS_ANNOTATION_GAP; // 3px + } /* * number of visible widths (the last one may be part height), @@ -662,8 +670,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * @param endColumn * @param canvasHeight */ - protected void drawWrappedWidth(Graphics g, int ypos, int startColumn, - int endColumn, int canvasHeight) + protected void drawWrappedWidth(Graphics g, final int ypos, + final int startColumn, final int endColumn, + final int canvasHeight) { ViewportRanges ranges = av.getRanges(); int viewportWidth = ranges.getViewportWidth(); @@ -710,7 +719,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.isShowAnnotation()) { - g.translate(0, cHeight + ypos + SEQS_ANNOTATION_GAP); + final int yShift = cHeight + ypos + SEQS_ANNOTATION_GAP; + g.translate(0, yShift); if (annotations == null) { annotations = new AnnotationPanel(av); @@ -718,7 +728,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI annotations.renderer.drawComponent(annotations, av, g, -1, startColumn, endx + 1); - g.translate(0, -cHeight - ypos - SEQS_ANNOTATION_GAP); + g.translate(0, -yShift); } g.setClip(clip); g.translate(-xOffset, 0); diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 0b62629..d0859b8 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -272,29 +272,44 @@ public class SeqPanel extends JPanel int alignmentHeight = av.getAlignment().getHeight(); if (av.getWrapAlignment()) { - int hgap = charHeight; - if (av.getScaleAboveWrapped()) - { - hgap += charHeight; - } + seqCanvas.calculateWrappedGeometry(seqCanvas.getWidth(), + seqCanvas.getHeight()); + // int gapHeight = charHeight; + // if (av.getScaleAboveWrapped()) + // { + // gapHeight += charHeight; + // } + // + // final int alignmentHeightPixels = gapHeight + // + alignmentHeight * charHeight; + // int cHeight = alignmentHeightPixels; + // if (av.isShowAnnotation()) + // { + // cHeight += (seqCanvas.getAnnotationHeight() + + // SeqCanvas.SEQS_ANNOTATION_GAP); + // } - final int alignmentHeightPixels = alignmentHeight * charHeight + hgap; - final int annotationHeight = seqCanvas.getAnnotationHeight(); - final int cHeight = alignmentHeightPixels + annotationHeight - + SeqCanvas.SEQS_ANNOTATION_GAP; + /* + * yPos modulo repeating width height + */ + int yOffsetPx = y % seqCanvas.wrappedRepeatHeightPx; - int yOffsetPx = y % cHeight; // yPos below repeating width(s) - if (yOffsetPx >= alignmentHeightPixels - + SeqCanvas.SEQS_ANNOTATION_GAP) + /* + * height of sequences plus space / scale above, + * plus gap between sequences and annotations + */ + int alignmentHeightPixels = seqCanvas.wrappedSpaceAboveAlignment + + alignmentHeight * charHeight + + SeqCanvas.SEQS_ANNOTATION_GAP; + if (yOffsetPx >= alignmentHeightPixels) { /* - * mouse is over annotations; find annotation index, also + * mouse is over annotations; find annotation index, also set * last sequence above (for backwards compatible behaviour) */ AlignmentAnnotation[] anns = av.getAlignment() .getAlignmentAnnotation(); - int rowOffsetPx = yOffsetPx - alignmentHeightPixels - - SeqCanvas.SEQS_ANNOTATION_GAP; + int rowOffsetPx = yOffsetPx - alignmentHeightPixels; annIndex = AnnotationPanel.getRowIndex(rowOffsetPx, anns); seqIndex = alignmentHeight - 1; } @@ -303,7 +318,7 @@ public class SeqPanel extends JPanel /* * mouse is over sequence (or the space above sequences) */ - yOffsetPx -= hgap; + yOffsetPx -= seqCanvas.wrappedSpaceAboveAlignment; if (yOffsetPx >= 0) { seqIndex = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); @@ -333,7 +348,6 @@ public class SeqPanel extends JPanel int startRes = av.getRanges().getStartRes(); if (av.getWrapAlignment()) { - int hgap = av.getCharHeight(); if (av.getScaleAboveWrapped()) { @@ -358,7 +372,7 @@ public class SeqPanel extends JPanel // allow for wrapped view scrolled right (possible from Overview) int startOffset = startRes % cwidth; res = wrappedBlock * cwidth + startOffset - + +Math.min(cwidth - 1, x / av.getCharWidth()); + + Math.min(cwidth - 1, x / av.getCharWidth()); } else { @@ -908,6 +922,7 @@ public class SeqPanel extends JPanel { lastMousePosition = null; setToolTipText(null); + lastTooltip = null; ap.alignFrame.statusBar.setText(""); return; } @@ -1026,20 +1041,26 @@ public class SeqPanel extends JPanel @Override public Point getToolTipLocation(MouseEvent event) { - int x = event.getX(), w = getWidth(); - int wdth = (w - x < 200) ? -(w / 2) : 5; // switch sides when tooltip is too - // close to edge + if (tooltipText == null || tooltipText.length() <= 6) + { + lastp = null; + return null; + } + + int x = event.getX(); + int w = getWidth(); + // switch sides when tooltip is too close to edge + int wdth = (w - x < 200) ? -(w / 2) : 5; Point p = lastp; if (!event.isShiftDown() || p == null) { - p = (tooltipText != null && tooltipText.length() > 6) - ? new Point(event.getX() + wdth, event.getY() - 20) - : null; + p = new Point(event.getX() + wdth, event.getY() - 20); + lastp = p; } /* - * TODO: try to modify position region is not obcured by tooltip + * TODO: try to set position so region is not obscured by tooltip */ - return lastp = p; + return p; } String lastTooltip; diff --git a/test/jalview/gui/SeqCanvasTest.java b/test/jalview/gui/SeqCanvasTest.java index 5298680..73aeb79 100644 --- a/test/jalview/gui/SeqCanvasTest.java +++ b/test/jalview/gui/SeqCanvasTest.java @@ -29,10 +29,10 @@ import jalview.io.FileLoader; import java.awt.Font; import java.awt.FontMetrics; -import junit.extensions.PA; - import org.testng.annotations.Test; +import junit.extensions.PA; + public class SeqCanvasTest { /** @@ -97,8 +97,8 @@ public class SeqCanvasTest assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3); /* - * reduce canvas height by 1 pixel - should not be enough height - * to draw 3 widths + * reduce canvas height by 1 pixel + * - should not be enough height to draw 3 widths */ canvasHeight -= 1; testee.calculateWrappedGeometry(canvasWidth, canvasHeight); @@ -170,11 +170,11 @@ public class SeqCanvasTest canvasWidth += 8; wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight); - assertEquals(wrappedWidth, 27); + assertEquals(wrappedWidth, 27); // 8px not enough canvasWidth += 1; wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight); - assertEquals(wrappedWidth, 28); + assertEquals(wrappedWidth, 28); // 9px is enough /* * now West but not East scale - lose 39 pixels or 4 columns @@ -190,11 +190,11 @@ public class SeqCanvasTest canvasWidth += 2; wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight); - assertEquals(wrappedWidth, 24); + assertEquals(wrappedWidth, 24); // 2px not enough canvasWidth += 1; wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight); - assertEquals(wrappedWidth, 25); + assertEquals(wrappedWidth, 25); // 3px is enough /* * turn off scales left and right, make width exactly 157 columns @@ -256,15 +256,16 @@ public class SeqCanvasTest 2 * charHeight); int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx"); assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()) - + annotationHeight); + + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight); assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1); /* - * repeat height is 17 * (2 + 15) = 289 + annotationHeight = 507 - * make canvas height 2 * 289 + 3 * charHeight so just enough to - * draw 2 widths and the first sequence of a third + * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510 + * make canvas height 2 of these plus 3 charHeights + * so just enough to draw 2 widths, gap + scale + the first sequence of a third */ - canvasHeight = charHeight * (17 * 2 + 3) + 2 * annotationHeight; + canvasHeight = charHeight * (17 * 2 + 3) + + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP); testee.calculateWrappedGeometry(canvasWidth, canvasHeight); assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3); @@ -287,7 +288,8 @@ public class SeqCanvasTest * reduce height to enough for 2 widths and not quite a third * i.e. two repeating heights + spacer + sequence - 1 pixel */ - canvasHeight = charHeight * (16 * 2 + 2) + 2 * annotationHeight - 1; + canvasHeight = charHeight * (16 * 2 + 2) + + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1; testee.calculateWrappedGeometry(canvasWidth, canvasHeight); assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2); diff --git a/test/jalview/gui/SeqPanelTest.java b/test/jalview/gui/SeqPanelTest.java index 4177acc..d5c012e 100644 --- a/test/jalview/gui/SeqPanelTest.java +++ b/test/jalview/gui/SeqPanelTest.java @@ -138,7 +138,7 @@ public class SeqPanelTest } @Test(groups = "Functional") - public void testFindMousePosition_wrapped() + public void testFindMousePosition_wrapped_annotations() { Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true"); Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); @@ -236,6 +236,7 @@ public class SeqPanelTest /* * cursor below sequences, in 3-pixel gap above annotations + * method reports index of nearest sequence above */ y += 1; evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, @@ -246,7 +247,6 @@ public class SeqPanelTest /* * cursor still in the gap above annotations, now at the bottom of it - * method reports index of nearest sequence above */ y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2 evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, @@ -576,6 +576,93 @@ public class SeqPanelTest assertEquals(pos.seqIndex, 0); assertEquals(pos.annotationIndex, -1); } + @Test(groups = "Functional") + public void testFindMousePosition_wrapped_noAnnotations() + { + Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false"); + Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( + "examples/uniref50.fa", DataSourceType.FILE); + AlignViewportI av = alignFrame.getViewport(); + av.setScaleAboveWrapped(false); + av.setScaleLeftWrapped(false); + av.setScaleRightWrapped(false); + alignFrame.alignPanel.paintAlignment(false, false); + + final int charHeight = av.getCharHeight(); + final int charWidth = av.getCharWidth(); + final int alignmentHeight = av.getAlignment().getHeight(); + + // sanity checks: + assertTrue(charHeight > 0); + assertTrue(charWidth > 0); + assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0); + + SeqPanel testee = alignFrame.alignPanel.getSeqPanel(); + int x = 0; + int y = 0; + + /* + * mouse at top left of wrapped panel; there is a gap of charHeight + * above the alignment + */ + MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, + 0, 0, 0, false, 0); + MousePos pos = testee.findMousePosition(evt); + assertEquals(pos.column, 0); + assertEquals(pos.seqIndex, -1); // above sequences + assertEquals(pos.annotationIndex, -1); + + /* + * cursor over top of first sequence + */ + y = charHeight; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of last sequence + */ + y = charHeight * (1 + alignmentHeight) - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor below sequences, at top of charHeight gap between widths + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor below sequences, at top of charHeight gap between widths + */ + y += charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at the top of the first sequence, second width + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + } @BeforeClass(alwaysRun = true) public static void setUpBeforeClass() throws Exception { -- 1.7.10.2