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 static org.testng.Assert.assertEquals;
25 import jalview.bin.Cache;
26 import jalview.datamodel.AlignmentI;
27 import jalview.io.DataSourceType;
28 import jalview.io.FileLoader;
29 import jalview.util.Platform;
32 import java.awt.FontMetrics;
34 import org.testng.Assert;
35 import org.testng.annotations.BeforeClass;
36 import org.testng.annotations.Test;
38 import junit.extensions.PA;
40 public class SeqCanvasTest
42 @BeforeClass(alwaysRun = true)
49 * Test the method that computes wrapped width in residues, height of wrapped
50 * widths in pixels, and the number of widths visible
52 @Test(groups = "Functional")
53 public void testCalculateWrappedGeometry_noAnnotations()
55 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
56 "examples/uniref50.fa", DataSourceType.FILE);
57 AlignViewport av = af.getViewport();
58 AlignmentI al = av.getAlignment();
59 assertEquals(al.getWidth(), 157);
60 assertEquals(al.getHeight(), 15);
61 av.getRanges().setStartEndSeq(0, 14);
63 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
65 av.setWrapAlignment(true);
66 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
67 int charHeight = av.getCharHeight();
68 int charWidth = av.getCharWidth();
69 Assert.assertTrue(charHeight == 17 && charWidth == 12
70 || charHeight == 19 && charWidth == 11,
71 "char height/width " + charHeight + "/" + charWidth);
73 // assertEquals(charHeight, Platform.isMac() ? 17 : 19);
74 // assertEquals(charWidth, Platform.isMac() ? 12 : 11);
77 * first with scales above, left, right
79 av.setShowAnnotation(false);
80 av.setScaleAboveWrapped(true);
81 av.setScaleLeftWrapped(true);
82 av.setScaleRightWrapped(true);
83 FontMetrics fm = testee.getFontMetrics(av.getFont());
84 int labelWidth = fm.stringWidth("000") + charWidth;
85 // BH 2020.03.22 It is not really necessary to be this detailed. Different
87 // always have slightly different parameters. StringgWidths are not
88 // necessarily linear sums of the letters involved.
89 // for example, the calculation for JavaScript is a float that has to be
91 // ..............................mac................PC................linux?
93 labelWidth == 39 || labelWidth == 35 || labelWidth == 36);// 3 * 9 +
105 * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
106 * take the whole multiple of character widths
108 int canvasWidth = 400;
109 int canvasHeight = 300;
110 int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
111 int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
112 assertEquals(wrappedWidth, residueColumns);
113 assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
114 assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
115 assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
117 int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
118 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
119 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
122 * repeat height is 17 * (2 + 15) = 289
123 * make canvas height 2 * 289 + 3 * charHeight so just enough to
124 * draw 2 widths and the first sequence of a third
126 canvasHeight = charHeight * (17 * 2 + 3);
127 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
128 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
131 * reduce canvas height by 1 pixel
132 * - should not be enough height to draw 3 widths
135 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
136 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
139 * turn off scale above - can now fit in 2 and a bit widths
141 av.setScaleAboveWrapped(false);
142 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
143 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
146 * reduce height to enough for 2 widths and not quite a third
147 * i.e. two repeating heights + spacer + sequence - 1 pixel
149 canvasHeight = charHeight * (16 * 2 + 2) - 1;
150 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
151 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
154 * make canvas width enough for scales and 20 residues
156 canvasWidth = 2 * labelWidth + 20 * charWidth;
157 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
159 assertEquals(wrappedWidth, 20);
162 * reduce width by 1 pixel - rounds down to 19 residues
165 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
167 assertEquals(wrappedWidth, 19);
170 * turn off West scale - adds labelWidth (39) to available for residues
171 * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
173 av.setScaleLeftWrapped(false);
174 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
176 assertEquals(wrappedWidth, 23);
179 * add 10 pixels to width to fit in another whole residue column
182 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
184 assertEquals(wrappedWidth, 23);
186 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
188 assertEquals(wrappedWidth, 24);
191 * turn off East scale to gain 39 more pixels (3 columns remainder 3)
193 av.setScaleRightWrapped(false);
194 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
196 assertEquals(wrappedWidth, 27);
199 * add 9 pixels to width to gain a residue column
202 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
204 assertEquals(wrappedWidth, 27); // 8px not enough
206 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
208 assertEquals(wrappedWidth, 28); // 9px is enough
211 * now West but not East scale - lose 39 pixels or 4 columns
213 av.setScaleLeftWrapped(true);
214 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
216 assertEquals(wrappedWidth, 24);
219 * adding 3 pixels to width regains one column
222 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
224 assertEquals(wrappedWidth, Platform.isMac() ? 24 : 25); // 2px not enough
226 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
228 assertEquals(wrappedWidth, 25); // 3px is enough
231 * turn off scales left and right, make width exactly 157 columns
233 av.setScaleLeftWrapped(false);
234 canvasWidth = al.getWidth() * charWidth;
235 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
236 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
240 * Test the method that computes wrapped width in residues, height of wrapped
241 * widths in pixels, and the number of widths visible
243 @Test(groups = "Functional")
244 public void testCalculateWrappedGeometry_withAnnotations()
246 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
247 "examples/uniref50.fa", DataSourceType.FILE);
248 AlignViewport av = af.getViewport();
249 AlignmentI al = av.getAlignment();
250 assertEquals(al.getWidth(), 157);
251 assertEquals(al.getHeight(), 15);
253 av.setWrapAlignment(true);
254 av.getRanges().setStartEndSeq(0, 14);
255 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
256 int charHeight = av.getCharHeight();
257 int charWidth = av.getCharWidth();
260 charHeight == 17 && charWidth == 12
261 || charHeight == 19 && charWidth == 11,
262 "char height/width " + charHeight + "/" + charWidth);
263 // assertEquals(charHeight, Platform.isMac() ? 17 : 19);
264 // assertEquals(charWidth, Platform.isMac() ? 12 : 11);
266 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
269 * first with scales above, left, right
271 av.setShowAnnotation(true);
272 av.setScaleAboveWrapped(true);
273 av.setScaleLeftWrapped(true);
274 av.setScaleRightWrapped(true);
276 FontMetrics fm = testee.getFontMetrics(av.getFont());
277 int labelWidth = fm.stringWidth("000") + charWidth;
278 // BH 2020.03.22 It is not really necessary to be this detailed. Different
280 // always have slightly different parameters. StringgWidths are not
281 // necessarily linear sums of the letters involved.
282 // for example, the calculation for JavaScript is a float that has to be
284 // ..............................mac................PC................linux?
286 labelWidth == 39 || labelWidth == 35 || labelWidth == 36);// 3 * 9 +
296 // int labelWidth = fm.stringWidth("000") + charWidth;
297 // assertEquals(labelWidth,
298 // Platform.isMac() ? 3 * 9 + charWidth : 3 * 8 + charWidth);
300 int annotationHeight = testee.getAnnotationHeight();
303 * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
304 * take the whole multiple of character widths
306 int canvasWidth = 400;
307 int canvasHeight = 300;
308 int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
309 int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
310 assertEquals(wrappedWidth, residueColumns);
311 assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
312 assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
313 assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
315 int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
316 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
317 + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight);
318 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
321 * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510
322 * make canvas height 2 of these plus 3 charHeights
323 * so just enough to draw 2 widths, gap + scale + the first sequence of a third
325 canvasHeight = charHeight * (17 * 2 + 3)
326 + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP);
327 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
328 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
331 * reduce canvas height by 1 pixel - should not be enough height
335 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
336 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
339 * turn off scale above - can now fit in 2 and a bit widths
341 av.setScaleAboveWrapped(false);
342 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
343 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
346 * reduce height to enough for 2 widths and not quite a third
347 * i.e. two repeating heights + spacer + sequence - 1 pixel
349 canvasHeight = charHeight * (16 * 2 + 2)
350 + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1;
351 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
352 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
355 * add 1 pixel to height - should now get 3 widths drawn
358 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
359 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
363 * Test simulates loading an unwrapped alignment, shrinking it vertically so
364 * not all sequences are visible, then changing to wrapped mode. The ranges
365 * endSeq should be unchanged, but the vertical repeat height should include
368 @Test(groups = "Functional")
369 public void testCalculateWrappedGeometry_fromScrolled()
371 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
372 "examples/uniref50.fa", DataSourceType.FILE);
373 AlignViewport av = af.getViewport();
374 AlignmentI al = av.getAlignment();
375 assertEquals(al.getWidth(), 157);
376 assertEquals(al.getHeight(), 15);
377 av.getRanges().setStartEndSeq(0, 3);
378 av.setShowAnnotation(false);
379 av.setScaleAboveWrapped(true);
381 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
382 av.setWrapAlignment(true);
383 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
384 int charHeight = av.getCharHeight();
385 int charWidth = av.getCharWidth();
386 // Windows h=19, w=11; Mac (and Linux?) 17,11
387 Assert.assertTrue(charHeight == 17 && charWidth == 12
388 || charHeight == 19 && charWidth == 11,
389 "char height/width " + charHeight + "/" + charWidth);
390 int canvasWidth = 400;
391 int canvasHeight = 300;
392 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
393 int repeatingHeight = (int) PA.getValue(testee,
394 "wrappedRepeatHeightPx");
396 assertEquals(av.getRanges().getEndSeq(), 3,
397 "av.getRanges endseq=" + av.getRanges().getEndSeq() + " repht "
398 + repeatingHeight + " x="
399 + (charHeight * (2 + al.getHeight()))); // unchanged
400 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));