JAL-3087 include full alignment height in repeating wrapped height
[jalview.git] / test / jalview / gui / SeqCanvasTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.gui;
22
23 import static org.testng.Assert.assertEquals;
24
25 import jalview.datamodel.AlignmentI;
26 import jalview.io.DataSourceType;
27 import jalview.io.FileLoader;
28
29 import java.awt.Font;
30 import java.awt.FontMetrics;
31
32 import org.testng.annotations.Test;
33
34 import junit.extensions.PA;
35
36 public class SeqCanvasTest
37 {
38   /**
39    * Test the method that computes wrapped width in residues, height of wrapped
40    * widths in pixels, and the number of widths visible
41    */
42   @Test(groups = "Functional")
43   public void testCalculateWrappedGeometry_noAnnotations()
44   {
45     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
46             "examples/uniref50.fa", DataSourceType.FILE);
47     AlignViewport av = af.getViewport();
48     AlignmentI al = av.getAlignment();
49     assertEquals(al.getWidth(), 157);
50     assertEquals(al.getHeight(), 15);
51     av.getRanges().setStartEndSeq(0, 14);
52
53     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
54
55     av.setWrapAlignment(true);
56     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
57     int charHeight = av.getCharHeight();
58     int charWidth = av.getCharWidth();
59     assertEquals(charHeight, 17);
60     assertEquals(charWidth, 12);
61
62     /*
63      * first with scales above, left, right
64      */
65     av.setShowAnnotation(false);
66     av.setScaleAboveWrapped(true);
67     av.setScaleLeftWrapped(true);
68     av.setScaleRightWrapped(true);
69     FontMetrics fm = testee.getFontMetrics(av.getFont());
70     int labelWidth = fm.stringWidth("000") + charWidth;
71     assertEquals(labelWidth, 39); // 3 x 9 + charWidth
72
73     /*
74      * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
75      * take the whole multiple of character widths
76      */
77     int canvasWidth = 400;
78     int canvasHeight = 300;
79     int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
80     int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
81     assertEquals(wrappedWidth, residueColumns);
82     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
83     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
84     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
85             2 * charHeight);
86     int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
87     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
88     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
89
90     /*
91      * repeat height is 17 * (2 + 15) = 289
92      * make canvas height 2 * 289 + 3 * charHeight so just enough to
93      * draw 2 widths and the first sequence of a third
94      */
95     canvasHeight = charHeight * (17 * 2 + 3);
96     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
97     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
98
99     /*
100      * reduce canvas height by 1 pixel - should not be enough height
101      * to draw 3 widths
102      */
103     canvasHeight -= 1;
104     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
105     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
106
107     /*
108      * turn off scale above - can now fit in 2 and a bit widths
109      */
110     av.setScaleAboveWrapped(false);
111     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
112     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
113
114     /*
115      * reduce height to enough for 2 widths and not quite a third
116      * i.e. two repeating heights + spacer + sequence - 1 pixel
117      */
118     canvasHeight = charHeight * (16 * 2 + 2) - 1;
119     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
120     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
121
122     /*
123      * make canvas width enough for scales and 20 residues
124      */
125     canvasWidth = 2 * labelWidth + 20 * charWidth;
126     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
127             canvasHeight);
128     assertEquals(wrappedWidth, 20);
129
130     /*
131      * reduce width by 1 pixel - rounds down to 19 residues
132      */
133     canvasWidth -= 1;
134     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
135             canvasHeight);
136     assertEquals(wrappedWidth, 19);
137
138     /*
139      * turn off West scale - adds labelWidth (39) to available for residues
140      * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
141      */
142     av.setScaleLeftWrapped(false);
143     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
144             canvasHeight);
145     assertEquals(wrappedWidth, 23);
146
147     /*
148      * add 10 pixels to width to fit in another whole residue column
149      */
150     canvasWidth += 9;
151     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
152             canvasHeight);
153     assertEquals(wrappedWidth, 23);
154     canvasWidth += 1;
155     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
156             canvasHeight);
157     assertEquals(wrappedWidth, 24);
158
159     /*
160      * turn off East scale to gain 39 more pixels (3 columns remainder 3)
161      */
162     av.setScaleRightWrapped(false);
163     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
164             canvasHeight);
165     assertEquals(wrappedWidth, 27);
166
167     /*
168      * add 9 pixels to width to gain a residue column
169      */
170     canvasWidth += 8;
171     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
172             canvasHeight);
173     assertEquals(wrappedWidth, 27);
174     canvasWidth += 1;
175     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
176             canvasHeight);
177     assertEquals(wrappedWidth, 28);
178
179     /*
180      * now West but not East scale - lose 39 pixels or 4 columns
181      */
182     av.setScaleLeftWrapped(true);
183     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
184             canvasHeight);
185     assertEquals(wrappedWidth, 24);
186
187     /*
188      * adding 3 pixels to width regains one column
189      */
190     canvasWidth += 2;
191     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
192             canvasHeight);
193     assertEquals(wrappedWidth, 24);
194     canvasWidth += 1;
195     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
196             canvasHeight);
197     assertEquals(wrappedWidth, 25);
198
199     /*
200      * turn off scales left and right, make width exactly 157 columns
201      */
202     av.setScaleLeftWrapped(false);
203     canvasWidth = al.getWidth() * charWidth;
204     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
205     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
206   }
207
208   /**
209    * Test the method that computes wrapped width in residues, height of wrapped
210    * widths in pixels, and the number of widths visible
211    */
212   @Test(groups = "Functional")
213   public void testCalculateWrappedGeometry_withAnnotations()
214   {
215     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
216             "examples/uniref50.fa", DataSourceType.FILE);
217     AlignViewport av = af.getViewport();
218     AlignmentI al = av.getAlignment();
219     assertEquals(al.getWidth(), 157);
220     assertEquals(al.getHeight(), 15);
221   
222     av.setWrapAlignment(true);
223     av.getRanges().setStartEndSeq(0, 14);
224     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
225     int charHeight = av.getCharHeight();
226     int charWidth = av.getCharWidth();
227     assertEquals(charHeight, 17);
228     assertEquals(charWidth, 12);
229   
230     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
231   
232     /*
233      * first with scales above, left, right
234      */
235     av.setShowAnnotation(true);
236     av.setScaleAboveWrapped(true);
237     av.setScaleLeftWrapped(true);
238     av.setScaleRightWrapped(true);
239     FontMetrics fm = testee.getFontMetrics(av.getFont());
240     int labelWidth = fm.stringWidth("000") + charWidth;
241     assertEquals(labelWidth, 39); // 3 x 9 + charWidth
242     int annotationHeight = testee.getAnnotationHeight();
243
244     /*
245      * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
246      * take the whole multiple of character widths
247      */
248     int canvasWidth = 400;
249     int canvasHeight = 300;
250     int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
251     int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
252     assertEquals(wrappedWidth, residueColumns);
253     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
254     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
255     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
256             2 * charHeight);
257     int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
258     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
259             + annotationHeight);
260     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
261   
262     /*
263      * repeat height is 17 * (2 + 15) = 289 + annotationHeight = 507
264      * make canvas height 2 * 289 + 3 * charHeight so just enough to
265      * draw 2 widths and the first sequence of a third
266      */
267     canvasHeight = charHeight * (17 * 2 + 3) + 2 * annotationHeight;
268     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
269     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
270   
271     /*
272      * reduce canvas height by 1 pixel - should not be enough height
273      * to draw 3 widths
274      */
275     canvasHeight -= 1;
276     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
277     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
278   
279     /*
280      * turn off scale above - can now fit in 2 and a bit widths
281      */
282     av.setScaleAboveWrapped(false);
283     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
284     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
285   
286     /*
287      * reduce height to enough for 2 widths and not quite a third
288      * i.e. two repeating heights + spacer + sequence - 1 pixel
289      */
290     canvasHeight = charHeight * (16 * 2 + 2) + 2 * annotationHeight - 1;
291     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
292     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
293
294     /*
295      * add 1 pixel to height - should now get 3 widths drawn
296      */
297     canvasHeight += 1;
298     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
299     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
300   }
301
302   /**
303    * Test simulates loading an unwrapped alignment, shrinking it vertically so
304    * not all sequences are visible, then changing to wrapped mode. The ranges
305    * endSeq should be unchanged, but the vertical repeat height should include
306    * all sequences.
307    */
308   @Test(groups = "Functional")
309   public void testCalculateWrappedGeometry_fromScrolled()
310   {
311     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
312             "examples/uniref50.fa", DataSourceType.FILE);
313     AlignViewport av = af.getViewport();
314     AlignmentI al = av.getAlignment();
315     assertEquals(al.getWidth(), 157);
316     assertEquals(al.getHeight(), 15);
317     av.getRanges().setStartEndSeq(0, 3);
318     av.setShowAnnotation(false);
319     av.setScaleAboveWrapped(true);
320
321     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
322
323     av.setWrapAlignment(true);
324     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
325     int charHeight = av.getCharHeight();
326     int charWidth = av.getCharWidth();
327     assertEquals(charHeight, 17);
328     assertEquals(charWidth, 12);
329
330     int canvasWidth = 400;
331     int canvasHeight = 300;
332     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
333
334     assertEquals(av.getRanges().getEndSeq(), 3); // unchanged
335     int repeatingHeight = (int) PA.getValue(testee,
336             "wrappedRepeatHeightPx");
337     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
338   }
339 }