int cursorY = 0;
- int charHeight = 0;
-
- int charWidth = 0;
-
private AnnotationPanel annotations;
/*
public SeqCanvas(AlignmentPanel ap)
{
this.av = ap.av;
- updateViewport();
fr = new FeatureRenderer(ap);
sr = new SequenceRenderer(av);
setLayout(new BorderLayout());
return fr;
}
- private void updateViewport()
- {
- charHeight = av.getCharHeight();
- charWidth = av.getCharWidth();
- }
-
/**
* Draws the scale above a region of a wrapped alignment, consisting of a
* column number every major interval (10 columns).
*/
private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
{
- updateViewport();
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
/*
* white fill the scale space (for the fastPaint case)
void drawVerticalScale(Graphics g, int startx, int endx, int ypos,
boolean left)
{
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
ypos += charHeight;
if (av.hasHiddenColumns())
try
{
- updateViewport();
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
ViewportRanges ranges = av.getRanges();
int startRes = ranges.getStartRes();
@Override
public void paintComponent(Graphics g)
{
- updateViewport();
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
BufferedImage lcimg = img; // take reference since other threads may null
// img and call later.
super.paintComponent(g);
*/
public int getWrappedCanvasWidth(int canvasWidth)
{
+ int charWidth = av.getCharWidth();
+
FontMetrics fm = getFontMetrics(av.getFont());
labelWidthEast = 0;
public void drawWrappedPanel(Graphics g, int canvasWidth,
int canvasHeight, final int startColumn)
{
- updateViewport();
-
int wrappedWidthInResidues = calculateWrappedGeometry(canvasWidth,
canvasHeight);
* draw one width at a time (including any scales or annotation shown),
* until we have run out of either alignment or vertical space available
*/
- int yposMax = canvasHeight;
- // ensure room for at least one sequence
- yposMax -= wrappedSpaceAboveAlignment - charHeight;
int ypos = wrappedSpaceAboveAlignment;
int maxWidth = ranges.getVisibleAlignmentWidth();
int start = startColumn;
- while ((ypos <= yposMax) && (start < maxWidth))
+ int currentWidth = 0;
+ while ((currentWidth < wrappedVisibleWidths) && (start < maxWidth))
{
int endColumn = Math
.min(maxWidth, start + wrappedWidthInResidues - 1);
drawWrappedWidth(g, ypos, start, endColumn, canvasHeight);
ypos += wrappedRepeatHeightPx;
start += wrappedWidthInResidues;
+ currentWidth++;
}
drawWrappedDecorators(g, startColumn);
*/
protected int calculateWrappedGeometry(int canvasWidth, int canvasHeight)
{
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
/*
* width of labels in pixels left and right (if shown)
*/
/*
* vertical space in pixels between wrapped widths of alignment
+ * - one character height, or two if scale above is drawn
*/
wrappedSpaceAboveAlignment = charHeight
* (av.getScaleAboveWrapped() ? 2 : 1);
wrappedRepeatHeightPx += getAnnotationHeight();
/*
- * number of visible widths (the last one may be part height)
+ * number of residue columns we can show in each row;
+ * this is just canvas width less scale left and right (if shown),
+ * as a whole multiple of character widths
+ */
+ int wrappedWidthInResidues = (canvasWidth - labelWidthEast - labelWidthWest)
+ / charWidth;
+
+ /*
+ * number of visible widths (the last one may be part height),
+ * ensuring a part height includes at least one sequence
*/
ViewportRanges ranges = av.getRanges();
int xMax = ranges.getVisibleAlignmentWidth();
/*
* limit visibleWidths to not exceed width of alignment
*/
- int viewportWidth = ranges.getViewportWidth();
- int maxWidths = (xMax - ranges.getStartRes()) / viewportWidth;
- if (xMax % viewportWidth > 0)
+ int maxWidths = (xMax - ranges.getStartRes()) / wrappedWidthInResidues;
+ if (xMax % wrappedWidthInResidues > 0)
{
maxWidths++;
}
wrappedVisibleWidths = Math.min(wrappedVisibleWidths, maxWidths);
- /*
- * number of whole width residue columns we can show in each row
- */
- int wrappedWidthInResidues = (canvasWidth - labelWidthEast - labelWidthWest)
- / charWidth;
return wrappedWidthInResidues;
}
protected void drawWrappedWidth(Graphics g, int ypos,
int startColumn, int endColumn, int canvasHeight)
{
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
ViewportRanges ranges = av.getRanges();
int viewportWidth = ranges.getViewportWidth();
*/
protected void drawWrappedDecorators(Graphics g, int startColumn)
{
+ int charWidth = av.getCharWidth();
+
g.setFont(av.getFont());
g.setColor(Color.black);
protected void drawHiddenColumnMarkers(Graphics g, int ypos,
int startColumn, int endColumn)
{
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
g.setColor(Color.blue);
HiddenColumns hidden = av.getAlignment().getHiddenColumns();
List<Integer> positions = hidden.findHiddenRegionPositions();
public void drawPanel(Graphics g1, final int startRes, final int endRes,
final int startSeq, final int endSeq, final int yOffset)
{
- updateViewport();
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
if (!av.hasHiddenColumns())
{
draw(g1, startRes, endRes, startSeq, endSeq, yOffset);
private void draw(Graphics g, int startRes, int endRes, int startSeq,
int endSeq, int offset)
{
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
g.setFont(av.getFont());
sr.prepare(g, av.isRenderGaps());
void drawGroupsBoundaries(Graphics g1, int startRes, int endRes,
int startSeq, int endSeq, int offset)
{
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+
Graphics2D g = (Graphics2D) g1;
//
// ///////////////////////////////////
return false;
}
boolean wrapped = av.getWrapAlignment();
-
try
{
fastPaint = !noFastPaint;
fastpainting = fastPaint;
- updateViewport();
-
/*
* to avoid redrawing the whole visible region, we instead
* redraw just the minimal regions to remove previous highlights
ViewportRanges ranges = av.getRanges();
int viewportWidth = ranges.getViewportWidth();
+ int charWidth = av.getCharWidth();
/**
* draw full height alignment in the second last row, last columns, if the
}
/*
+ * draw newly visible columns in last wrapped width (none if we
+ * have reached the end of the alignment)
* y-offset for drawing last width is height of widths above,
* plus one gap row
*/
+ wrappedSpaceAboveAlignment;
int endRes = ranges.getEndRes();
endRes += widthsAbove * viewportWidth;
- endRes = Math.min(endRes, ranges.getVisibleAlignmentWidth());
int startRes = endRes - columns + 1;
/*
gg.setFont(av.getFont());
gg.setColor(Color.black);
- drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight);
+ if (startRes < ranges.getVisibleAlignmentWidth())
+ {
+ drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight);
+ }
/*
* and finally, white fill any space below the visible alignment
{
return;
}
+ int charWidth = av.getCharWidth();
int canvasHeight = getHeight();
ViewportRanges ranges = av.getRanges();
{
return false;
}
-
+ int charHeight = av.getCharHeight();
+
boolean matchFound = false;
+ calculateWrappedGeometry(getWidth(), getHeight());
int wrappedWidth = av.getWrappedWidth();
- int wrappedHeight = getRepeatHeightWrapped();
+ int wrappedHeight = wrappedRepeatHeightPx;
ViewportRanges ranges = av.getRanges();
int canvasHeight = getHeight();
return matchFound;
}
-
- /**
- * Answers the height in pixels of a repeating section of the wrapped
- * alignment, including space above, scale above if shown, sequences, and
- * annotation panel if shown
- *
- * @return
- */
- protected int getRepeatHeightWrapped()
- {
- // gap (and maybe scale) above
- int repeatHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
-
- // add sequences
- repeatHeight += av.getRanges().getViewportHeight() * charHeight;
-
- // add annotations panel height if shown
- repeatHeight += getAnnotationHeight();
-
- return repeatHeight;
- }
}
--- /dev/null
+package jalview.gui;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.AlignmentI;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+
+import junit.extensions.PA;
+
+import org.testng.annotations.Test;
+
+import sun.swing.SwingUtilities2;
+
+public class SeqCanvasTest
+{
+ /**
+ * Test the method that computes wrapped width in residues, height of wrapped
+ * widths in pixels, and the number of widths visible
+ */
+ @Test(groups = "Functional")
+ public void testCalculateWrappedGeometry_noAnnotations()
+ {
+ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+ "examples/uniref50.fa", DataSourceType.FILE);
+ AlignViewport av = af.getViewport();
+ AlignmentI al = av.getAlignment();
+ assertEquals(al.getWidth(), 157);
+ assertEquals(al.getHeight(), 15);
+
+ av.setWrapAlignment(true);
+ av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+ assertEquals(charHeight, 17);
+ assertEquals(charWidth, 12);
+
+ SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
+
+ /*
+ * first with scales above, left, right
+ */
+ av.setShowAnnotation(false);
+ av.setScaleAboveWrapped(true);
+ av.setScaleLeftWrapped(true);
+ av.setScaleRightWrapped(true);
+ FontMetrics fm = SwingUtilities2.getFontMetrics(testee, av.getFont());
+ int labelWidth = fm.stringWidth("00000"); // width of 3 digits and 2 spaces
+ assertEquals(labelWidth, 45); // note this is not 5 * charWidth
+
+ /*
+ * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
+ * take the whole multiple of character widths
+ */
+ int canvasWidth = 400;
+ int canvasHeight = 300;
+ int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
+ int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+ assertEquals(wrappedWidth, residueColumns);
+ assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
+ assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
+ assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
+ 2 * charHeight);
+ int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
+ assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
+ assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
+
+ /*
+ * repeat height is 17 * (2 + 15) = 289
+ * make canvas height 2 * 289 + 3 * charHeight so just enough to
+ * draw 2 widths and the first sequence of a third
+ */
+ canvasHeight = charHeight * (17 * 2 + 3);
+ testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+ assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+
+ /*
+ * reduce canvas height by 1 pixel - should not be enough height
+ * to draw 3 widths
+ */
+ canvasHeight -= 1;
+ testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+ assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
+
+ /*
+ * turn off scale above - can now fit in 2 and a bit widths
+ */
+ av.setScaleAboveWrapped(false);
+ testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+ assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
+
+ /*
+ * 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) - 1;
+ testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+ assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
+
+ /*
+ * make canvas width enough for scales and 20 residues
+ */
+ canvasWidth = 2 * labelWidth + 20 * charWidth;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 20);
+
+ /*
+ * reduce width by 1 pixel - rounds down to 19 residues
+ */
+ canvasWidth -= 1;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 19);
+
+ /*
+ * turn off West scale - adds labelWidth (45) to available for residues
+ * which with the 11 remainder makes 56 which is 4 more charWidths rem 8
+ */
+ av.setScaleLeftWrapped(false);
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 23);
+
+ /*
+ * add 4 pixels to width to fit in another whole residue column
+ */
+ canvasWidth += 3;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 23);
+ canvasWidth += 1;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 24);
+
+ /*
+ * turn off East scale to gain 45 more pixels (3 columns remainder 9)
+ */
+ av.setScaleRightWrapped(false);
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 27);
+
+ /*
+ * add 3 pixels to width to gain a residue column
+ */
+ canvasWidth += 3;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 28);
+
+ /*
+ * now West but not East scale - lose 45 pixels or 4 columns
+ */
+ av.setScaleLeftWrapped(true);
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 24);
+
+ /*
+ * adding 9 pixels to width regains one column
+ */
+ canvasWidth += 8;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 24);
+ canvasWidth += 1;
+ wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
+ canvasHeight);
+ assertEquals(wrappedWidth, 25);
+
+ /*
+ * turn off scales left and right, make width exactly 157 columns
+ */
+ av.setScaleLeftWrapped(false);
+ canvasWidth = al.getWidth() * charWidth;
+ testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
+ assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
+ }
+}