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().getVisibleWidth();
284 int alheight = av.getAlignment().getHeight();
286 int annotationHeight = 0;
287 AnnotationLabels labels = null;
289 if (av.isShowAnnotation())
291 AnnotationPanel ap = new AnnotationPanel(av);
292 annotationHeight = ap.adjustPanelHeight();
293 labels = new AnnotationLabels(av);
295 int hgap = avcharHeight;
296 if (av.getScaleAboveWrapped())
298 hgap += avcharHeight;
301 int cHeight = alheight * avcharHeight + hgap + annotationHeight;
303 int rowSize = av.getRanges().getViewportWidth();
305 // hardwired italic IDs in applet currently
306 Font italic = new Font(av.getFont().getName(), Font.ITALIC,
307 av.getFont().getSize());
311 * draw repeating sequence ids until out of sequence data or
312 * out of visible space, whichever comes first
315 int row = av.getRanges().getStartRes();
316 while ((ypos <= getHeight()) && (row < maxwidth))
318 for (int i = starty; i < alheight; i++)
321 SequenceI s = av.getAlignment().getSequenceAt(i);
322 // gg.setFont(italic);
327 drawIdString(gg, hiddenRows, s, i, 0, ypos);
332 gg.translate(0, ypos + (alheight * avcharHeight));
333 labels.drawComponent(gg, getSize().width);
334 gg.translate(0, -ypos - (alheight * avcharHeight));
341 public void setHighlighted(List<SequenceI> list)
343 searchResults = list;
347 void drawMarker(int i, int starty, int yoffset)
349 SequenceI[] hseqs = av.getAlignment()
350 .getHiddenSequences().hiddenSequences;
351 // Use this method here instead of calling hiddenSeq adjust
353 int hSize = hseqs.length;
356 int lastIndex = i - 1;
357 int nextIndex = i + 1;
359 for (int j = 0; j < hSize; j++)
361 if (hseqs[j] != null)
363 if (j - 1 < hiddenIndex)
367 if (j - 1 < lastIndex)
371 if (j - 1 < nextIndex)
378 boolean below = (hiddenIndex > lastIndex + 1);
379 boolean above = (nextIndex > hiddenIndex + 1);
381 gg.setColor(Color.blue);
386 { getSize().width - avcharHeight,
387 getSize().width - avcharHeight, getSize().width },
389 { (i - starty) * avcharHeight + yoffset,
390 (i - starty) * avcharHeight + yoffset + avcharHeight / 4,
391 (i - starty) * avcharHeight + yoffset },
398 { getSize().width - avcharHeight,
399 getSize().width - avcharHeight, getSize().width },
401 { (i - starty + 1) * avcharHeight + yoffset,
402 (i - starty + 1) * avcharHeight + yoffset
404 (i - starty + 1) * avcharHeight + yoffset },
410 boolean setHiddenFont(SequenceI seq)
412 Font bold = new Font(av.getFont().getName(), Font.BOLD,
413 av.getFont().getSize());
415 if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
424 * Respond to viewport range changes (e.g. alignment panel was scrolled). Both
425 * scrolling and resizing change viewport ranges. Scrolling changes both start
426 * and end points, but resize only changes end values. Here we only want to
427 * fastpaint on a scroll, with resize using a normal paint, so scroll events
428 * are identified as changes to the horizontal or vertical start value.
430 * In unwrapped mode, only responds to a vertical scroll, as horizontal scroll
431 * leaves sequence ids unchanged. In wrapped mode, only vertical scroll is
432 * provided, but it generates a change of "startres" which does require an
436 public void propertyChange(PropertyChangeEvent evt)
438 String propertyName = evt.getPropertyName();
439 if (propertyName.equals(ViewportRanges.STARTSEQ)
440 || (av.getWrapAlignment()
441 && propertyName.equals(ViewportRanges.STARTRES)))
443 fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
445 else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ))
447 fastPaint(((int[]) evt.getNewValue())[1]
448 - ((int[]) evt.getOldValue())[1]);
450 else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT))