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.
21 package jalview.appletgui;
23 import jalview.datamodel.SequenceI;
24 import jalview.viewmodel.ViewportListenerI;
25 import jalview.viewmodel.ViewportRanges;
27 import java.awt.Color;
29 import java.awt.Graphics;
30 import java.awt.Image;
31 import java.awt.Panel;
32 import java.beans.PropertyChangeEvent;
33 import java.util.List;
35 public class IdCanvas extends Panel implements ViewportListenerI
37 protected AlignViewport av;
39 protected boolean showScores = true;
41 protected int maxIdLength = -1;
43 protected String maxIdStr = null;
51 boolean fastPaint = false;
53 List<SequenceI> searchResults;
55 public IdCanvas(AlignViewport av)
59 PaintRefresher.Register(this, av.getSequenceSetId());
60 av.getRanges().addPropertyChangeListener(this);
63 public void drawIdString(Graphics gg, boolean hiddenRows, SequenceI s,
64 int i, int starty, int ypos)
66 int charHeight = av.getCharHeight();
68 if (searchResults != null && searchResults.contains(s))
70 gg.setColor(Color.black);
71 gg.fillRect(0, ((i - starty) * charHeight) + ypos, getSize().width,
73 gg.setColor(Color.white);
75 else if (av.getSelectionGroup() != null
76 && av.getSelectionGroup().getSequences(null).contains(s))
78 gg.setColor(Color.lightGray);
79 gg.fillRect(0, ((i - starty) * charHeight) + ypos, getSize().width,
81 gg.setColor(Color.white);
85 gg.setColor(av.getSequenceColour(s));
86 gg.fillRect(0, ((i - starty) * charHeight) + ypos, getSize().width,
88 gg.setColor(Color.black);
91 gg.drawString(s.getDisplayId(av.getShowJVSuffix()), 0,
92 ((i - starty) * charHeight) + ypos + charHeight
97 drawMarker(i, starty, ypos);
102 public void fastPaint(int vertical)
104 if (gg == null || av.getWrapAlignment())
110 ViewportRanges ranges = av.getRanges();
112 gg.copyArea(0, 0, getSize().width, imgHeight, 0,
113 -vertical * av.getCharHeight());
115 int ss = ranges.getStartSeq(), es = ranges.getEndSeq(), transY = 0;
116 if (vertical > 0) // scroll down
119 if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
123 ss = ranges.getStartSeq();
127 transY = imgHeight - ((vertical + 1) * av.getCharHeight());
130 else if (vertical < 0)
133 if (es > ranges.getEndSeq())
135 es = ranges.getEndSeq();
139 gg.translate(0, transY);
143 gg.translate(0, -transY);
150 public void update(Graphics g)
156 public void paint(Graphics g)
158 if (getSize().height < 0 || getSize().width < 0)
165 g.drawImage(image, 0, 0, this);
169 imgHeight = getSize().height;
170 imgHeight -= imgHeight % av.getCharHeight();
177 if (image == null || imgHeight != image.getHeight(this))
179 image = createImage(getSize().width, imgHeight);
180 gg = image.getGraphics();
181 gg.setFont(av.getFont());
184 // Fill in the background
185 gg.setColor(Color.white);
186 Font italic = new Font(av.getFont().getName(), Font.ITALIC,
187 av.getFont().getSize());
190 gg.fillRect(0, 0, getSize().width, getSize().height);
191 drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq());
192 g.drawImage(image, 0, 0, this);
196 * local copy of av.getCharHeight set at top of drawIds
198 private int avcharHeight;
200 void drawIds(int starty, int endy)
202 avcharHeight = av.getCharHeight();
204 Color currentColor = Color.white;
205 Color currentTextColor = Color.black;
207 final boolean doHiddenCheck = av.isDisplayReferenceSeq()
208 || av.hasHiddenRows();
209 boolean hiddenRows = av.hasHiddenRows() && av.getShowHiddenMarkers();
211 if (av.getWrapAlignment())
213 drawIdsWrapped(starty, doHiddenCheck, hiddenRows);
217 // Now draw the id strings
219 for (int i = starty; i <= endy; i++)
221 seq = av.getAlignment().getSequenceAt(i);
226 // hardwired italic IDs in applet currently
227 Font italic = new Font(av.getFont().getName(), Font.ITALIC,
228 av.getFont().getSize());
230 // boolean isrep=false;
237 // Selected sequence colours
238 if ((searchResults != null) && searchResults.contains(seq))
240 currentColor = Color.black;
241 currentTextColor = Color.white;
243 else if ((av.getSelectionGroup() != null)
244 && av.getSelectionGroup().getSequences(null).contains(seq))
246 currentColor = Color.lightGray;
247 currentTextColor = Color.black;
251 currentColor = av.getSequenceColour(seq);
252 currentTextColor = Color.black;
255 gg.setColor(currentColor);
256 // TODO: isrep could be used to highlight the representative in a
258 gg.fillRect(0, (i - starty) * avcharHeight, getSize().width,
260 gg.setColor(currentTextColor);
262 gg.drawString(seq.getDisplayId(av.getShowJVSuffix()), 0,
263 (((i - starty) * avcharHeight) + avcharHeight)
264 - (avcharHeight / 5));
268 drawMarker(i, starty, 0);
274 * Draws sequence ids in wrapped mode
277 * @param doHiddenCheck
280 protected void drawIdsWrapped(int starty, final boolean doHiddenCheck,
283 int maxwidth = av.getAlignment().getWidth();
284 int alheight = av.getAlignment().getHeight();
286 if (av.hasHiddenColumns())
288 maxwidth = av.getAlignment().getHiddenColumns()
289 .findColumnPosition(maxwidth) - 1;
292 int annotationHeight = 0;
293 AnnotationLabels labels = null;
295 if (av.isShowAnnotation())
297 AnnotationPanel ap = new AnnotationPanel(av);
298 annotationHeight = ap.adjustPanelHeight();
299 labels = new AnnotationLabels(av);
301 int hgap = avcharHeight;
302 if (av.getScaleAboveWrapped())
304 hgap += avcharHeight;
307 int cHeight = alheight * avcharHeight + hgap + annotationHeight;
309 int rowSize = av.getRanges().getViewportWidth();
311 // hardwired italic IDs in applet currently
312 Font italic = new Font(av.getFont().getName(), Font.ITALIC,
313 av.getFont().getSize());
317 * draw repeating sequence ids until out of sequence data or
318 * out of visible space, whichever comes first
321 int row = av.getRanges().getStartRes();
322 while ((ypos <= getHeight()) && (row < maxwidth))
324 for (int i = starty; i < alheight; i++)
327 SequenceI s = av.getAlignment().getSequenceAt(i);
328 // gg.setFont(italic);
333 drawIdString(gg, hiddenRows, s, i, 0, ypos);
338 gg.translate(0, ypos + (alheight * avcharHeight));
339 labels.drawComponent(gg, getSize().width);
340 gg.translate(0, -ypos - (alheight * avcharHeight));
347 public void setHighlighted(List<SequenceI> list)
349 searchResults = list;
353 void drawMarker(int i, int starty, int yoffset)
355 SequenceI[] hseqs = av.getAlignment()
356 .getHiddenSequences().hiddenSequences;
357 // Use this method here instead of calling hiddenSeq adjust
359 int hSize = hseqs.length;
362 int lastIndex = i - 1;
363 int nextIndex = i + 1;
365 for (int j = 0; j < hSize; j++)
367 if (hseqs[j] != null)
369 if (j - 1 < hiddenIndex)
373 if (j - 1 < lastIndex)
377 if (j - 1 < nextIndex)
384 boolean below = (hiddenIndex > lastIndex + 1);
385 boolean above = (nextIndex > hiddenIndex + 1);
387 gg.setColor(Color.blue);
392 { getSize().width - avcharHeight,
393 getSize().width - avcharHeight, getSize().width },
395 { (i - starty) * avcharHeight + yoffset,
396 (i - starty) * avcharHeight + yoffset + avcharHeight / 4,
397 (i - starty) * avcharHeight + yoffset },
404 { getSize().width - avcharHeight,
405 getSize().width - avcharHeight, getSize().width },
407 { (i - starty + 1) * avcharHeight + yoffset,
408 (i - starty + 1) * avcharHeight + yoffset
410 (i - starty + 1) * avcharHeight + yoffset },
416 boolean setHiddenFont(SequenceI seq)
418 Font bold = new Font(av.getFont().getName(), Font.BOLD,
419 av.getFont().getSize());
421 if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
430 * Respond to viewport range changes (e.g. alignment panel was scrolled). Both
431 * scrolling and resizing change viewport ranges. Scrolling changes both start
432 * and end points, but resize only changes end values. Here we only want to
433 * fastpaint on a scroll, with resize using a normal paint, so scroll events
434 * are identified as changes to the horizontal or vertical start value.
436 * In unwrapped mode, only responds to a vertical scroll, as horizontal scroll
437 * leaves sequence ids unchanged. In wrapped mode, only vertical scroll is
438 * provided, but it generates a change of "startres" which does require an
442 public void propertyChange(PropertyChangeEvent evt)
444 String propertyName = evt.getPropertyName();
445 if (propertyName.equals(ViewportRanges.STARTSEQ)
446 || (av.getWrapAlignment()
447 && propertyName.equals(ViewportRanges.STARTRES)))
449 fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
451 else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ))
453 fastPaint(((int[]) evt.getNewValue())[1]
454 - ((int[]) evt.getOldValue())[1]);
456 else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT))