+ column = hiddenColumns.visibleToAbsoluteColumn(startRes + x);
+ if (column > row_annotations.length - 1)
+ {
+ break;
+ }
+ }
+ else
+ {
+ column = startRes + x;
+ }
+
+ if ((row_annotations == null)
+ || (row_annotations.length <= column)
+ || (row_annotations[column] == null))
+ {
+ validRes = false;
+ }
+ else
+ {
+ validRes = true;
+ }
+ final String displayChar = validRes
+ ? row_annotations[column].displayCharacter
+ : null;
+ if (x > -1)
+ {
+ if (activeRow == i)
+ {
+ g.setColor(Color.red);
+
+ if (columnSelection != null)
+ {
+ if (columnSelection.contains(column))
+ {
+ fillRect(g, x * charWidth, y, charWidth, charHeight);
+ }
+ }
+ }
+ if (row.getInvalidStrucPos() > x)
+ {
+ g.setColor(Color.orange);
+ fillRect(g, x * charWidth, y, charWidth, charHeight);
+ }
+ else if (row.getInvalidStrucPos() == x)
+ {
+ g.setColor(Color.orange.darker());
+ fillRect(g, x * charWidth, y, charWidth, charHeight);
+ }
+ if (validCharWidth && validRes && displayChar != null
+ && (displayChar.length() > 0))
+ {
+ // Graphics2D gg = (g);
+ float fmWidth = fm.charsWidth(displayChar.toCharArray(), 0,
+ displayChar.length());
+
+ /*
+ * shrink label width to fit in column, if that is
+ * both configured and necessary
+ */
+ boolean scaledToFit = false;
+ float fmScaling = 1f;
+ if (scaleColLabel && fmWidth > charWidth)
+ {
+ scaledToFit = true;
+ fmScaling = charWidth;
+ fmScaling /= fmWidth;
+ // and update the label's width to reflect the scaling.
+ fmWidth = charWidth;
+ }
+
+ charOffset = (int) ((charWidth - fmWidth) / 2f);
+
+ if (row_annotations[column].colour == null)
+ {
+ g2d.setColor(Color.black);
+ }
+ else
+ {
+ g2d.setColor(row_annotations[column].colour);
+ }
+
+ /*
+ * draw the label, unless it is the same secondary structure
+ * symbol (excluding RNA Helix) as the previous column
+ */
+ final int xPos = (x * charWidth) + charOffset;
+ final int yPos = y + iconOffset;
+
+ /*
+ * translate to drawing position _before_ applying any scaling
+ */
+ g2d.translate(xPos, yPos);
+ if (scaledToFit)
+ {
+ /*
+ * use a scaling transform to make the label narrower
+ * (JalviewJS doesn't have Font.deriveFont(AffineTransform))
+ */
+ g2d.transform(
+ AffineTransform.getScaleInstance(fmScaling, 1.0));
+ }
+ if (column == 0 || row.graph > 0)
+ {
+ g2d.drawString(displayChar, 0, 0);
+ }
+ else if (row_annotations[column - 1] == null || (labelAllCols
+ || !displayChar.equals(
+ row_annotations[column - 1].displayCharacter)
+ || (displayChar.length() < 2
+ && row_annotations[column].secondaryStructure == ' ')))
+ {
+ g2d.drawString(displayChar, 0, 0);
+ }
+ if (scaledToFit)
+ {
+ /*
+ * undo scaling before translating back
+ * (restoring saved transform does NOT work in JS PDFGraphics!)
+ */
+ g2d.transform(AffineTransform
+ .getScaleInstance(1D / fmScaling, 1.0));
+ }
+ g2d.translate(-xPos, -yPos);
+ }
+ }
+ if (row.hasIcons)
+ {
+ char ss = validRes ? row_annotations[column].secondaryStructure
+ : '-';
+
+ if (ss == '(')
+ {
+ // distinguish between forward/backward base-pairing
+ if (displayChar.indexOf(')') > -1)
+ {
+
+ ss = ')';
+
+ }
+ }
+ if (ss == '[')
+ {
+ if ((displayChar.indexOf(']') > -1))
+ {
+ ss = ']';
+
+ }
+ }
+ if (ss == '{')
+ {
+ // distinguish between forward/backward base-pairing
+ if (displayChar.indexOf('}') > -1)
+ {
+ ss = '}';
+
+ }
+ }
+ if (ss == '<')
+ {
+ // distinguish between forward/backward base-pairing
+ if (displayChar.indexOf('<') > -1)
+ {
+ ss = '>';
+
+ }
+ }
+ if (isRNA && (ss >= CHAR_A) && (ss <= CHAR_Z))
+ {
+ // distinguish between forward/backward base-pairing
+ int ssLowerCase = ss + UPPER_TO_LOWER;
+ // TODO would .equals() be safer here? or charAt(0)?
+ if (displayChar.indexOf(ssLowerCase) > -1)
+ {
+ ss = (char) ssLowerCase;
+ }
+ }
+
+ if (!validRes || (ss != lastSS))
+ {
+
+ if (x > -1)
+ {
+
+ // int nb_annot = x - temp;
+ // Console.info("\t type :"+lastSS+"\t x
+ // :"+x+"\t nbre
+ // annot :"+nb_annot);
+ switch (lastSS)
+ {
+ case '(': // Stem case for RNA secondary structure
+ case ')': // and opposite direction
+ drawStemAnnot(g, row_annotations, lastSSX, x, y,
+ iconOffset, startRes, column, validRes, validEnd);
+ // temp = x;
+ break;
+
+ case 'H':
+ if (!isRNA)
+ {
+ drawHelixAnnot(g, row_annotations, lastSSX, x, y,
+ iconOffset, startRes, column, validRes,
+ validEnd);
+ break;
+ }
+ // no break if isRNA - falls through to drawNotCanonicalAnnot!
+ case 'E':
+ if (!isRNA)
+ {
+ drawSheetAnnot(g, row_annotations, lastSSX, x, y,
+ iconOffset, startRes, column, validRes,
+ validEnd);
+ break;
+ }
+ // no break if isRNA - fall through to drawNotCanonicalAnnot!
+
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case '>':
+ case '<':
+ case 'A':
+ case 'a':
+ case 'B':
+ case 'b':
+ case 'C':
+ case 'c':
+ case 'D':
+ case 'd':
+ case 'e':
+ case 'F':
+ case 'f':
+ case 'G':
+ case 'g':
+ case 'h':
+ case 'I':
+ case 'i':
+ case 'J':
+ case 'j':
+ case 'K':
+ case 'k':
+ case 'L':
+ case 'l':
+ case 'M':
+ case 'm':
+ case 'N':
+ case 'n':
+ case 'O':
+ case 'o':
+ case 'P':
+ case 'p':
+ case 'Q':
+ case 'q':
+ case 'R':
+ case 'r':
+ case 'S':
+ case 's':
+ case 'T':
+ case 't':
+ case 'U':
+ case 'u':
+ case 'V':
+ case 'v':
+ case 'W':
+ case 'w':
+ case 'X':
+ case 'x':
+ case 'Y':
+ case 'y':
+ case 'Z':
+ case 'z':
+
+ Color nonCanColor = getNotCanonicalColor(lastSS);
+ drawNotCanonicalAnnot(g, nonCanColor, row_annotations,
+ lastSSX, x, y, iconOffset, startRes, column,
+ validRes, validEnd);
+ // temp = x;
+ break;
+ default:
+ g.setColor(GLYPHLINE_COLOR);
+ g.fillRect(lastSSX, y + 6 + iconOffset,
+ (x * charWidth) - lastSSX, 2);
+ // temp = x;
+ break;
+ }
+ }
+ if (validRes)
+ {
+ lastSS = ss;
+ }
+ else
+ {
+ lastSS = ' ';
+ }
+ if (x > -1)
+ {
+ lastSSX = (x * charWidth);
+ }
+ }