Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ViewportRanges | 32 | 180 | 86 |
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.viewmodel; | |
22 | ||
23 | import jalview.datamodel.AlignmentI; | |
24 | import jalview.datamodel.HiddenColumns; | |
25 | ||
26 | /** | |
27 | * Supplies and updates viewport properties relating to position such as: start | |
28 | * and end residues and sequences; ideally will serve hidden columns/rows too. | |
29 | * Intention also to support calculations for positioning, scrolling etc. such | |
30 | * as finding the middle of the viewport, checking for scrolls off screen | |
31 | */ | |
32 | public class ViewportRanges extends ViewportProperties | |
33 | { | |
34 | public static final String STARTRES = "startres"; | |
35 | ||
36 | public static final String ENDRES = "endres"; | |
37 | ||
38 | public static final String STARTSEQ = "startseq"; | |
39 | ||
40 | public static final String ENDSEQ = "endseq"; | |
41 | ||
42 | public static final String STARTRESANDSEQ = "startresandseq"; | |
43 | ||
44 | public static final String MOVE_VIEWPORT = "move_viewport"; | |
45 | ||
46 | private boolean wrappedMode = false; | |
47 | ||
48 | // start residue of viewport | |
49 | private int startRes; | |
50 | ||
51 | // end residue of viewport | |
52 | private int endRes; | |
53 | ||
54 | // start sequence of viewport | |
55 | private int startSeq; | |
56 | ||
57 | // end sequence of viewport | |
58 | private int endSeq; | |
59 | ||
60 | // alignment | |
61 | private AlignmentI al; | |
62 | ||
63 | /** | |
64 | * Constructor | |
65 | * | |
66 | * @param alignment | |
67 | * the viewport's alignment | |
68 | */ | |
69 | 586 | public ViewportRanges(AlignmentI alignment) |
70 | { | |
71 | // initial values of viewport settings | |
72 | 586 | this.startRes = 0; |
73 | 586 | this.endRes = alignment.getWidth() - 1; |
74 | 586 | this.startSeq = 0; |
75 | 586 | this.endSeq = alignment.getHeight() - 1; |
76 | 586 | this.al = alignment; |
77 | } | |
78 | ||
79 | /** | |
80 | * Get alignment width in cols, including hidden cols | |
81 | */ | |
82 | 1040 | public int getAbsoluteAlignmentWidth() |
83 | { | |
84 | 1040 | return al.getWidth(); |
85 | } | |
86 | ||
87 | /** | |
88 | * Get alignment height in rows, including hidden rows | |
89 | */ | |
90 | 743 | public int getAbsoluteAlignmentHeight() |
91 | { | |
92 | 743 | return al.getHeight() + al.getHiddenSequences().getSize(); |
93 | } | |
94 | ||
95 | /** | |
96 | * Get alignment width in cols, excluding hidden cols | |
97 | */ | |
98 | 4704 | public int getVisibleAlignmentWidth() |
99 | { | |
100 | 4704 | return al.getVisibleWidth(); |
101 | } | |
102 | ||
103 | /** | |
104 | * Get alignment height in rows, excluding hidden rows | |
105 | */ | |
106 | 4350 | public int getVisibleAlignmentHeight() |
107 | { | |
108 | 4350 | return al.getHeight(); |
109 | } | |
110 | ||
111 | /** | |
112 | * Set first residue visible in the viewport, and retain the current width. | |
113 | * Fires a property change event. | |
114 | * | |
115 | * @param res | |
116 | * residue position | |
117 | */ | |
118 | 134 | public void setStartRes(int res) |
119 | { | |
120 | 134 | int width = getViewportWidth(); |
121 | 134 | setStartEndRes(res, res + width - 1); |
122 | } | |
123 | ||
124 | /** | |
125 | * Set start and end residues at the same time. This method only fires one | |
126 | * event for the two changes, and should be used in preference to separate | |
127 | * calls to setStartRes and setEndRes. | |
128 | * | |
129 | * @param start | |
130 | * the start residue | |
131 | * @param end | |
132 | * the end residue | |
133 | */ | |
134 | 1339 | public void setStartEndRes(int start, int end) |
135 | { | |
136 | 1339 | int[] oldvalues = updateStartEndRes(start, end); |
137 | 1339 | int oldstartres = oldvalues[0]; |
138 | 1339 | int oldendres = oldvalues[1]; |
139 | ||
140 | 1339 | changeSupport.firePropertyChange(STARTRES, oldstartres, startRes); |
141 | 1339 | if (oldstartres == startRes) |
142 | { | |
143 | // event won't be fired if start positions are same | |
144 | // fire an event for the end positions in case they changed | |
145 | 1212 | changeSupport.firePropertyChange(ENDRES, oldendres, endRes); |
146 | } | |
147 | } | |
148 | ||
149 | /** | |
150 | * Update start and end residue values, adjusting for width constraints if | |
151 | * necessary | |
152 | * | |
153 | * @param start | |
154 | * start residue | |
155 | * @param end | |
156 | * end residue | |
157 | * @return array containing old start and end residue values | |
158 | */ | |
159 | 1462 | private int[] updateStartEndRes(int start, int end) |
160 | { | |
161 | 1462 | int oldstartres = this.startRes; |
162 | ||
163 | /* | |
164 | * if not wrapped, don't leave white space at the right margin | |
165 | */ | |
166 | 1462 | int lastColumn = getVisibleAlignmentWidth() - 1; |
167 | 1462 | if (!wrappedMode && (start > lastColumn)) |
168 | { | |
169 | 4 | startRes = Math.max(lastColumn, 0); |
170 | } | |
171 | 1458 | else if (start < 0) |
172 | { | |
173 | 4 | startRes = 0; |
174 | } | |
175 | else | |
176 | { | |
177 | 1454 | startRes = start; |
178 | } | |
179 | ||
180 | 1462 | int oldendres = this.endRes; |
181 | 1462 | if (end < 0) |
182 | { | |
183 | 7 | endRes = 0; |
184 | } | |
185 | 1455 | else if (!wrappedMode && (end > lastColumn)) |
186 | { | |
187 | 301 | endRes = Math.max(lastColumn, 0); |
188 | } | |
189 | else | |
190 | { | |
191 | 1154 | endRes = end; |
192 | } | |
193 | 1462 | return new int[] { oldstartres, oldendres }; |
194 | } | |
195 | ||
196 | /** | |
197 | * Set the first sequence visible in the viewport, maintaining the height. If | |
198 | * the viewport would extend past the last sequence, sets the viewport so it | |
199 | * sits at the bottom of the alignment. Fires a property change event. | |
200 | * | |
201 | * @param seq | |
202 | * sequence position | |
203 | */ | |
204 | 703 | public void setStartSeq(int seq) |
205 | { | |
206 | 703 | int startseq = seq; |
207 | 703 | int height = getViewportHeight(); |
208 | 703 | if (startseq + height - 1 > getVisibleAlignmentHeight() - 1) |
209 | { | |
210 | 52 | startseq = getVisibleAlignmentHeight() - height; |
211 | } | |
212 | 703 | setStartEndSeq(startseq, startseq + height - 1); |
213 | } | |
214 | ||
215 | /** | |
216 | * Set start and end sequences at the same time. The viewport height may | |
217 | * change. This method only fires one event for the two changes, and should be | |
218 | * used in preference to separate calls to setStartSeq and setEndSeq. | |
219 | * | |
220 | * @param start | |
221 | * the start sequence | |
222 | * @param end | |
223 | * the end sequence | |
224 | */ | |
225 | 1779 | public void setStartEndSeq(int start, int end) |
226 | { | |
227 | // jalview.bin.Console.outPrintln("ViewportRange setStartEndSeq " + start + | |
228 | // " " + end); | |
229 | 1779 | int[] oldvalues = updateStartEndSeq(start, end); |
230 | 1779 | int oldstartseq = oldvalues[0]; |
231 | 1779 | int oldendseq = oldvalues[1]; |
232 | ||
233 | 1779 | changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq); |
234 | 1779 | if (oldstartseq == startSeq) |
235 | { | |
236 | // event won't be fired if start positions are the same | |
237 | // fire in case the end positions changed | |
238 | 1694 | changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq); |
239 | } | |
240 | } | |
241 | ||
242 | /** | |
243 | * Update start and end sequence values, adjusting for height constraints if | |
244 | * necessary | |
245 | * | |
246 | * @param start | |
247 | * start sequence | |
248 | * @param end | |
249 | * end sequence | |
250 | * @return array containing old start and end sequence values | |
251 | */ | |
252 | 1902 | private int[] updateStartEndSeq(int start, int end) |
253 | { | |
254 | 1902 | int oldstartseq = this.startSeq; |
255 | 1902 | int visibleHeight = getVisibleAlignmentHeight(); |
256 | 1902 | if (start > visibleHeight - 1) |
257 | { | |
258 | 3 | startSeq = Math.max(visibleHeight - 1, 0); |
259 | } | |
260 | 1899 | else if (start < 0) |
261 | { | |
262 | 54 | startSeq = 0; |
263 | } | |
264 | else | |
265 | { | |
266 | 1845 | startSeq = start; |
267 | } | |
268 | ||
269 | 1902 | int oldendseq = this.endSeq; |
270 | 1902 | if (end >= visibleHeight) |
271 | { | |
272 | 368 | endSeq = Math.max(visibleHeight - 1, 0); |
273 | } | |
274 | 1534 | else if (end < 0) |
275 | { | |
276 | 76 | endSeq = 0; |
277 | } | |
278 | else | |
279 | { | |
280 | 1458 | endSeq = end; |
281 | } | |
282 | 1902 | return new int[] { oldstartseq, oldendseq }; |
283 | } | |
284 | ||
285 | /** | |
286 | * Set the last sequence visible in the viewport. Fires a property change | |
287 | * event. | |
288 | * | |
289 | * @param seq | |
290 | * sequence position in the range [0, height) | |
291 | */ | |
292 | 26 | public void setEndSeq(int seq) |
293 | { | |
294 | // BH 2018.04.18 added safety for seq < 0; comment about not being >= height | |
295 | 26 | setStartEndSeq(Math.max(0, seq + 1 - getViewportHeight()), seq); |
296 | } | |
297 | ||
298 | /** | |
299 | * Set start residue and start sequence together (fires single event). The | |
300 | * event supplies a pair of old values and a pair of new values: [old start | |
301 | * residue, old start sequence] and [new start residue, new start sequence] | |
302 | * | |
303 | * @param res | |
304 | * the start residue | |
305 | * @param seq | |
306 | * the start sequence | |
307 | */ | |
308 | 119 | public void setStartResAndSeq(int res, int seq) |
309 | { | |
310 | 119 | int width = getViewportWidth(); |
311 | 119 | int[] oldresvalues = updateStartEndRes(res, res + width - 1); |
312 | ||
313 | 119 | int startseq = seq; |
314 | 119 | int height = getViewportHeight(); |
315 | 119 | if (startseq + height - 1 > getVisibleAlignmentHeight() - 1) |
316 | { | |
317 | 1 | startseq = getVisibleAlignmentHeight() - height; |
318 | } | |
319 | 119 | int[] oldseqvalues = updateStartEndSeq(startseq, startseq + height - 1); |
320 | ||
321 | 119 | int[] old = new int[] { oldresvalues[0], oldseqvalues[0] }; |
322 | 119 | int[] newresseq = new int[] { startRes, startSeq }; |
323 | 119 | changeSupport.firePropertyChange(STARTRESANDSEQ, old, newresseq); |
324 | } | |
325 | ||
326 | /** | |
327 | * Get start residue of viewport | |
328 | */ | |
329 | 18162 | public int getStartRes() |
330 | { | |
331 | 18162 | return startRes; |
332 | } | |
333 | ||
334 | /** | |
335 | * Get end residue of viewport | |
336 | */ | |
337 | 14495 | public int getEndRes() |
338 | { | |
339 | 14495 | return endRes; |
340 | } | |
341 | ||
342 | /** | |
343 | * Get start sequence of viewport | |
344 | */ | |
345 | 10671 | public int getStartSeq() |
346 | { | |
347 | 10671 | return startSeq; |
348 | } | |
349 | ||
350 | /** | |
351 | * Get end sequence of viewport | |
352 | */ | |
353 | 6290 | public int getEndSeq() |
354 | { | |
355 | 6290 | return endSeq; |
356 | } | |
357 | ||
358 | /** | |
359 | * Set viewport width in residues, without changing startRes. Use in | |
360 | * preference to calculating endRes from the width, to avoid out by one | |
361 | * errors! Fires a property change event. | |
362 | * | |
363 | * @param w | |
364 | * width in residues | |
365 | */ | |
366 | 554 | public void setViewportWidth(int w) |
367 | { | |
368 | 554 | setStartEndRes(startRes, startRes + w - 1); |
369 | } | |
370 | ||
371 | /** | |
372 | * Set viewport height in residues, without changing startSeq. Use in | |
373 | * preference to calculating endSeq from the height, to avoid out by one | |
374 | * errors! Fires a property change event. | |
375 | * | |
376 | * @param h | |
377 | * height in sequences | |
378 | */ | |
379 | 534 | public void setViewportHeight(int h) |
380 | { | |
381 | 534 | setStartEndSeq(startSeq, startSeq + h - 1); |
382 | } | |
383 | ||
384 | /** | |
385 | * Set viewport horizontal start position and width. Use in preference to | |
386 | * calculating endRes from the width, to avoid out by one errors! Fires a | |
387 | * property change event. | |
388 | * | |
389 | * @param start | |
390 | * start residue | |
391 | * @param w | |
392 | * width in residues | |
393 | */ | |
394 | 632 | public void setViewportStartAndWidth(int start, int w) |
395 | { | |
396 | 632 | int vpstart = start; |
397 | 632 | if (vpstart < 0) |
398 | { | |
399 | 2 | vpstart = 0; |
400 | } | |
401 | ||
402 | /* | |
403 | * if not wrapped, don't leave white space at the right margin | |
404 | */ | |
405 | 632 | if (!wrappedMode) |
406 | { | |
407 | 374 | if ((w <= getVisibleAlignmentWidth()) |
408 | && (vpstart + w - 1 > getVisibleAlignmentWidth() - 1)) | |
409 | { | |
410 | 1 | vpstart = getVisibleAlignmentWidth() - w; |
411 | } | |
412 | ||
413 | } | |
414 | 632 | setStartEndRes(vpstart, vpstart + w - 1); |
415 | } | |
416 | ||
417 | /** | |
418 | * Set viewport vertical start position and height. Use in preference to | |
419 | * calculating endSeq from the height, to avoid out by one errors! Fires a | |
420 | * property change event. | |
421 | * | |
422 | * @param start | |
423 | * start sequence | |
424 | * @param h | |
425 | * height in sequences | |
426 | */ | |
427 | 502 | public void setViewportStartAndHeight(int start, int h) |
428 | { | |
429 | 502 | int vpstart = start; |
430 | ||
431 | 502 | int visHeight = getVisibleAlignmentHeight(); |
432 | 502 | if (vpstart < 0) |
433 | { | |
434 | 3 | vpstart = 0; |
435 | } | |
436 | 499 | else if (h <= visHeight && vpstart + h > visHeight) |
437 | // viewport height is less than the full alignment and we are running off | |
438 | // the bottom | |
439 | { | |
440 | 5 | vpstart = visHeight - h; |
441 | } | |
442 | // jalview.bin.Console.outPrintln("ViewportRanges setviewportStartAndHeight | |
443 | // " + vpstart | |
444 | // + " " + start + " " + h + " " + getVisibleAlignmentHeight()); | |
445 | ||
446 | 502 | setStartEndSeq(vpstart, vpstart + h - 1); |
447 | } | |
448 | ||
449 | /** | |
450 | * Get width of viewport in residues | |
451 | * | |
452 | * @return width of viewport | |
453 | */ | |
454 | 3518 | public int getViewportWidth() |
455 | { | |
456 | 3518 | return (endRes - startRes + 1); |
457 | } | |
458 | ||
459 | /** | |
460 | * Get height of viewport in residues | |
461 | * | |
462 | * @return height of viewport | |
463 | */ | |
464 | 1858 | public int getViewportHeight() |
465 | { | |
466 | 1858 | return (endSeq - startSeq + 1); |
467 | } | |
468 | ||
469 | /** | |
470 | * Scroll the viewport range vertically. Fires a property change event. | |
471 | * | |
472 | * @param up | |
473 | * true if scrolling up, false if down | |
474 | * | |
475 | * @return true if the scroll is valid | |
476 | */ | |
477 | 28 | public boolean scrollUp(boolean up) |
478 | { | |
479 | /* | |
480 | * if in unwrapped mode, scroll up or down one sequence row; | |
481 | * if in wrapped mode, scroll by one visible width of columns | |
482 | */ | |
483 | 28 | if (up) |
484 | { | |
485 | 18 | if (wrappedMode) |
486 | { | |
487 | 2 | pageUp(); |
488 | } | |
489 | else | |
490 | { | |
491 | 16 | if (startSeq < 1) |
492 | { | |
493 | 2 | return false; |
494 | } | |
495 | 14 | setStartSeq(startSeq - 1); |
496 | } | |
497 | } | |
498 | else | |
499 | { | |
500 | 10 | if (wrappedMode) |
501 | { | |
502 | 4 | pageDown(); |
503 | } | |
504 | else | |
505 | { | |
506 | 6 | if (endSeq >= getVisibleAlignmentHeight() - 1) |
507 | { | |
508 | 2 | return false; |
509 | } | |
510 | 4 | setStartSeq(startSeq + 1); |
511 | } | |
512 | } | |
513 | 24 | return true; |
514 | } | |
515 | ||
516 | /** | |
517 | * Scroll the viewport range horizontally. Fires a property change event. | |
518 | * | |
519 | * @param right | |
520 | * true if scrolling right, false if left | |
521 | * | |
522 | * @return true if the scroll is valid | |
523 | */ | |
524 | 24 | public boolean scrollRight(boolean right) |
525 | { | |
526 | 24 | if (!right) |
527 | { | |
528 | 18 | if (startRes < 1) |
529 | { | |
530 | 2 | return false; |
531 | } | |
532 | ||
533 | 16 | setStartRes(startRes - 1); |
534 | } | |
535 | else | |
536 | { | |
537 | 6 | if (endRes >= getVisibleAlignmentWidth() - 1) |
538 | { | |
539 | 2 | return false; |
540 | } | |
541 | ||
542 | 4 | setStartRes(startRes + 1); |
543 | } | |
544 | ||
545 | 20 | return true; |
546 | } | |
547 | ||
548 | /** | |
549 | * Scroll a wrapped alignment so that the specified residue is in the first | |
550 | * repeat of the wrapped view. Fires a property change event. Answers true if | |
551 | * the startRes changed, else false. | |
552 | * | |
553 | * @param res | |
554 | * residue position to scroll to NB visible position not absolute | |
555 | * alignment position | |
556 | * @return | |
557 | */ | |
558 | 8 | public boolean scrollToWrappedVisible(int res) |
559 | { | |
560 | 8 | int newStartRes = calcWrappedStartResidue(res); |
561 | 8 | if (newStartRes == startRes) |
562 | { | |
563 | 3 | return false; |
564 | } | |
565 | 5 | setStartRes(newStartRes); |
566 | ||
567 | 5 | return true; |
568 | } | |
569 | ||
570 | /** | |
571 | * Calculate wrapped start residue from visible start residue | |
572 | * | |
573 | * @param res | |
574 | * visible start residue | |
575 | * @return left column of panel res will be located in | |
576 | */ | |
577 | 10 | private int calcWrappedStartResidue(int res) |
578 | { | |
579 | 10 | int oldStartRes = startRes; |
580 | 10 | int width = getViewportWidth(); |
581 | ||
582 | 10 | boolean up = res < oldStartRes; |
583 | 10 | int widthsToScroll = Math.abs((res - oldStartRes) / width); |
584 | 10 | if (up) |
585 | { | |
586 | 2 | widthsToScroll++; |
587 | } | |
588 | ||
589 | 10 | int residuesToScroll = width * widthsToScroll; |
590 | 10 | int newStartRes = up ? oldStartRes - residuesToScroll |
591 | : oldStartRes + residuesToScroll; | |
592 | 10 | if (newStartRes < 0) |
593 | { | |
594 | 2 | newStartRes = 0; |
595 | } | |
596 | 10 | return newStartRes; |
597 | } | |
598 | ||
599 | /** | |
600 | * Scroll so that (x,y) is visible. Fires a property change event. | |
601 | * | |
602 | * @param x | |
603 | * x position in alignment (absolute position) | |
604 | * @param y | |
605 | * y position in alignment (absolute position) | |
606 | */ | |
607 | 5 | public void scrollToVisible(int x, int y) |
608 | { | |
609 | 16 | while (y < startSeq) |
610 | { | |
611 | 11 | scrollUp(true); |
612 | } | |
613 | 6 | while (y > endSeq) |
614 | { | |
615 | 1 | scrollUp(false); |
616 | } | |
617 | ||
618 | 5 | HiddenColumns hidden = al.getHiddenColumns(); |
619 | 18 | while (x < hidden.visibleToAbsoluteColumn(startRes)) |
620 | { | |
621 | 13 | if (!scrollRight(false)) |
622 | { | |
623 | 0 | break; |
624 | } | |
625 | } | |
626 | 6 | while (x > hidden.visibleToAbsoluteColumn(endRes)) |
627 | { | |
628 | 1 | if (!scrollRight(true)) |
629 | { | |
630 | 0 | break; |
631 | } | |
632 | } | |
633 | } | |
634 | ||
635 | /** | |
636 | * Set the viewport location so that a position is visible | |
637 | * | |
638 | * @param x | |
639 | * column to be visible: absolute position in alignment | |
640 | * @param y | |
641 | * row to be visible: absolute position in alignment | |
642 | */ | |
643 | 7 | public boolean setViewportLocation(int x, int y) |
644 | { | |
645 | 7 | boolean changedLocation = false; |
646 | ||
647 | // convert the x,y location to visible coordinates | |
648 | 7 | int visX = al.getHiddenColumns().absoluteToVisibleColumn(x); |
649 | 7 | int visY = al.getHiddenSequences().findIndexWithoutHiddenSeqs(y); |
650 | ||
651 | // if (vis_x,vis_y) is already visible don't do anything | |
652 | 7 | if (startRes > visX || visX > endRes |
653 | || startSeq > visY && visY > endSeq) | |
654 | { | |
655 | 6 | int[] old = new int[] { startRes, startSeq }; |
656 | 6 | int[] newresseq; |
657 | 6 | if (wrappedMode) |
658 | { | |
659 | 2 | int newstartres = calcWrappedStartResidue(visX); |
660 | 2 | setStartRes(newstartres); |
661 | 2 | newresseq = new int[] { startRes, startSeq }; |
662 | } | |
663 | else | |
664 | { | |
665 | // set the viewport x location to contain vis_x | |
666 | 4 | int newstartres = visX; |
667 | 4 | int width = getViewportWidth(); |
668 | 4 | if (newstartres + width - 1 > getVisibleAlignmentWidth() - 1) |
669 | { | |
670 | 2 | newstartres = getVisibleAlignmentWidth() - width; |
671 | } | |
672 | 4 | updateStartEndRes(newstartres, newstartres + width - 1); |
673 | ||
674 | // set the viewport y location to contain vis_y | |
675 | 4 | int newstartseq = visY; |
676 | 4 | int height = getViewportHeight(); |
677 | 4 | if (newstartseq + height - 1 > getVisibleAlignmentHeight() - 1) |
678 | { | |
679 | 1 | newstartseq = getVisibleAlignmentHeight() - height; |
680 | } | |
681 | 4 | updateStartEndSeq(newstartseq, newstartseq + height - 1); |
682 | ||
683 | 4 | newresseq = new int[] { startRes, startSeq }; |
684 | } | |
685 | 6 | changedLocation = true; |
686 | 6 | changeSupport.firePropertyChange(MOVE_VIEWPORT, old, newresseq); |
687 | } | |
688 | 7 | return changedLocation; |
689 | } | |
690 | ||
691 | /** | |
692 | * Adjust sequence position for page up. Fires a property change event. | |
693 | */ | |
694 | 12 | public void pageUp() |
695 | { | |
696 | 12 | if (wrappedMode) |
697 | { | |
698 | 8 | setStartRes(Math.max(0, getStartRes() - getViewportWidth())); |
699 | } | |
700 | else | |
701 | { | |
702 | 4 | setViewportStartAndHeight(startSeq - (endSeq - startSeq), |
703 | getViewportHeight()); | |
704 | } | |
705 | } | |
706 | ||
707 | /** | |
708 | * Adjust sequence position for page down. Fires a property change event. | |
709 | */ | |
710 | 17 | public void pageDown() |
711 | { | |
712 | 17 | if (wrappedMode) |
713 | { | |
714 | /* | |
715 | * if height is more than width (i.e. not all sequences fit on screen), | |
716 | * increase page down to height | |
717 | */ | |
718 | 10 | int newStart = getStartRes() |
719 | + Math.max(getViewportHeight(), getViewportWidth()); | |
720 | ||
721 | /* | |
722 | * don't page down beyond end of alignment, or if not all | |
723 | * sequences fit in the visible height | |
724 | */ | |
725 | 10 | if (newStart < getVisibleAlignmentWidth()) |
726 | { | |
727 | 7 | setStartRes(newStart); |
728 | } | |
729 | } | |
730 | else | |
731 | { | |
732 | 7 | setViewportStartAndHeight(endSeq, getViewportHeight()); |
733 | } | |
734 | } | |
735 | ||
736 | 104 | public void setWrappedMode(boolean wrapped) |
737 | { | |
738 | 104 | wrappedMode = wrapped; |
739 | } | |
740 | ||
741 | 116 | public boolean isWrappedMode() |
742 | { | |
743 | 116 | return wrappedMode; |
744 | } | |
745 | ||
746 | /** | |
747 | * Answers the vertical scroll position (0..) to set, given the visible column | |
748 | * that is at top left. | |
749 | * | |
750 | * <pre> | |
751 | * Example: | |
752 | * viewport width 40 columns (0-39, 40-79, 80-119...) | |
753 | * column 0 returns scroll position 0 | |
754 | * columns 1-40 return scroll position 1 | |
755 | * columns 41-80 return scroll position 2 | |
756 | * etc | |
757 | * </pre> | |
758 | * | |
759 | * @param topLeftColumn | |
760 | * (0..) | |
761 | * @return | |
762 | */ | |
763 | 813 | public int getWrappedScrollPosition(final int topLeftColumn) |
764 | { | |
765 | 813 | int w = getViewportWidth(); |
766 | ||
767 | /* | |
768 | * visible whole widths | |
769 | */ | |
770 | 813 | int scroll = topLeftColumn / w; |
771 | ||
772 | /* | |
773 | * add 1 for a part width if there is one | |
774 | */ | |
775 | 813 | scroll += topLeftColumn % w > 0 ? 1 : 0; |
776 | ||
777 | 813 | return scroll; |
778 | } | |
779 | ||
780 | /** | |
781 | * Answers the maximum wrapped vertical scroll value, given the column | |
782 | * position (0..) to show at top left of the visible region. | |
783 | * | |
784 | * @param topLeftColumn | |
785 | * @return | |
786 | */ | |
787 | 423 | public int getWrappedMaxScroll(int topLeftColumn) |
788 | { | |
789 | 423 | int scrollPosition = getWrappedScrollPosition(topLeftColumn); |
790 | ||
791 | /* | |
792 | * how many more widths could be drawn after this one? | |
793 | */ | |
794 | 423 | int columnsRemaining = getVisibleAlignmentWidth() - topLeftColumn; |
795 | 423 | int width = getViewportWidth(); |
796 | 423 | int widthsRemaining = columnsRemaining / width |
797 | 423 | + (columnsRemaining % width > 0 ? 1 : 0) - 1; |
798 | 423 | int maxScroll = scrollPosition + widthsRemaining; |
799 | ||
800 | 423 | return maxScroll; |
801 | } | |
802 | } |