JAL-883 - refactored and debugged arrow, stem and helix rendering code
authorjprocter <jprocter@compbio.dundee.ac.uk>
Thu, 4 Aug 2011 16:16:33 +0000 (17:16 +0100)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Thu, 4 Aug 2011 16:16:33 +0000 (17:16 +0100)
src/jalview/gui/AnnotationPanel.java

index 6418c76..050e9f2 100755 (executable)
@@ -886,7 +886,6 @@ public class AnnotationPanel extends JPanel implements MouseListener,
       scaleColLabel = row.scaleColLabel;
       lastSS = ' ';
       lastSSX = 0;
-
       if (row.graph > 0)
       {
         if (row.graphGroup > -1 && graphGroupDrawn[row.graphGroup])
@@ -949,7 +948,9 @@ public class AnnotationPanel extends JPanel implements MouseListener,
         continue;
       }
 
-      x = 0;
+      // first pass sets up state for drawing continuation from left-hand column
+      // of startRes
+      x = (startRes == 0) ? 0 : -1;
       while (x < endRes - startRes)
       {
         if (av.hasHiddenColumns)
@@ -975,175 +976,117 @@ public class AnnotationPanel extends JPanel implements MouseListener,
         {
           validRes = true;
         }
-
-        if (activeRow == i)
+        if (x > -1)
         {
-          g.setColor(Color.red);
-
-          if (av.getColumnSelection() != null)
+          if (activeRow == i)
           {
-            for (int n = 0; n < av.getColumnSelection().size(); n++)
-            {
-              int v = av.getColumnSelection().columnAt(n);
+            g.setColor(Color.red);
 
-              if (v == column)
+            if (av.getColumnSelection() != null)
+            {
+              for (int n = 0; n < av.getColumnSelection().size(); n++)
               {
-                g.fillRect(x * av.charWidth, y, av.charWidth, av.charHeight);
+                int v = av.getColumnSelection().columnAt(n);
+
+                if (v == column)
+                {
+                  g.fillRect(x * av.charWidth, y, av.charWidth,
+                          av.charHeight);
+                }
               }
             }
           }
-        }
 
-        if (av.validCharWidth && validRes
-                && row.annotations[column].displayCharacter != null
-                && (row.annotations[column].displayCharacter.length() > 0))
-        {
-
-          if (centreColLabels || scaleColLabel)
+          if (av.validCharWidth
+                  && validRes
+                  && row.annotations[column].displayCharacter != null
+                  && (row.annotations[column].displayCharacter.length() > 0))
           {
-            fmWidth = (float) fm.charsWidth(
-                    row.annotations[column].displayCharacter.toCharArray(),
-                    0, row.annotations[column].displayCharacter.length());
 
-            if (scaleColLabel)
+            if (centreColLabels || scaleColLabel)
             {
-              // justify the label and scale to fit in column
-              if (fmWidth > av.charWidth)
+              fmWidth = (float) fm.charsWidth(
+                      row.annotations[column].displayCharacter
+                              .toCharArray(), 0,
+                      row.annotations[column].displayCharacter.length());
+
+              if (scaleColLabel)
               {
-                // scale only if the current font isn't already small enough
-                fmScaling = av.charWidth;
-                fmScaling /= fmWidth;
-                g.setFont(ofont.deriveFont(AffineTransform
-                        .getScaleInstance(fmScaling, 1.0)));
-                // and update the label's width to reflect the scaling.
-                fmWidth = av.charWidth;
+                // justify the label and scale to fit in column
+                if (fmWidth > av.charWidth)
+                {
+                  // scale only if the current font isn't already small enough
+                  fmScaling = av.charWidth;
+                  fmScaling /= fmWidth;
+                  g.setFont(ofont.deriveFont(AffineTransform
+                          .getScaleInstance(fmScaling, 1.0)));
+                  // and update the label's width to reflect the scaling.
+                  fmWidth = av.charWidth;
+                }
               }
             }
-          }
-          else
-          {
-            fmWidth = (float) fm
-                    .charWidth(row.annotations[column].displayCharacter
-                            .charAt(0));
-          }
-          charOffset = (int) ((av.charWidth - fmWidth) / 2f);
+            else
+            {
+              fmWidth = (float) fm
+                      .charWidth(row.annotations[column].displayCharacter
+                              .charAt(0));
+            }
+            charOffset = (int) ((av.charWidth - fmWidth) / 2f);
 
-          if (row.annotations[column].colour == null)
-            g.setColor(Color.black);
-          else
-            g.setColor(row.annotations[column].colour);
+            if (row.annotations[column].colour == null)
+              g.setColor(Color.black);
+            else
+              g.setColor(row.annotations[column].colour);
 
-          if (column == 0 || row.graph > 0)
-          {
-            g.drawString(row.annotations[column].displayCharacter,
-                    (x * av.charWidth) + charOffset, y + iconOffset);
-          }
-          else if (row.annotations[column - 1] == null
-                  || (labelAllCols
-                          || !row.annotations[column].displayCharacter
-                                  .equals(row.annotations[column - 1].displayCharacter) || (row.annotations[column].displayCharacter
-                          .length() < 2 && row.annotations[column].secondaryStructure == ' ')))
-          {
-            g.drawString(row.annotations[column].displayCharacter, x
-                    * av.charWidth + charOffset, y + iconOffset);
+            if (column == 0 || row.graph > 0)
+            {
+              g.drawString(row.annotations[column].displayCharacter,
+                      (x * av.charWidth) + charOffset, y + iconOffset);
+            }
+            else if (row.annotations[column - 1] == null
+                    || (labelAllCols
+                            || !row.annotations[column].displayCharacter
+                                    .equals(row.annotations[column - 1].displayCharacter) || (row.annotations[column].displayCharacter
+                            .length() < 2 && row.annotations[column].secondaryStructure == ' ')))
+            {
+              g.drawString(row.annotations[column].displayCharacter, x
+                      * av.charWidth + charOffset, y + iconOffset);
+            }
+            g.setFont(ofont);
           }
-          g.setFont(ofont);
         }
-
         if (row.hasIcons)
         {
           if (!validRes
                   || (row.annotations[column].secondaryStructure != lastSS))
           {
-            switch (lastSS)
+            if (x > -1)
             {
-            case 'H':
-              g.setColor(HELIX_COLOUR);
-              if (MAC)
+              switch (lastSS)
               {
-                // Off by 1 offset when drawing rects and ovals
-                // to offscreen image on the MAC
-                g.fillRoundRect(lastSSX, y + 4 + iconOffset,
-                        (x * av.charWidth) - lastSSX, 7, 8, 8);
+              case 'H':
+                drawHelixAnnot(g, row, lastSSX, x, y, iconOffset, startRes,
+                        column, validRes, validEnd);
                 break;
-              }
-
-              int sCol = (lastSSX / av.charWidth) + startRes;
-              int x1 = lastSSX;
-              int x2 = (x * av.charWidth);
 
-              if (sCol == 0
-                      || row.annotations[sCol - 1] == null
-                      || row.annotations[sCol - 1].secondaryStructure != 'H')
-              {
-                g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90,
-                        180);
-                x1 += av.charWidth / 2;
-              }
+              case 'E':
+                drawSheetAnnot(g, row, lastSSX, x, y, iconOffset, startRes,
+                        column, validRes, validEnd);
+                break;
 
-              if (!validRes || row.annotations[column] == null
-                      || row.annotations[column].secondaryStructure != 'H')
-              {
-                g.fillArc((x * av.charWidth) - av.charWidth, y + 4
-                        + iconOffset, av.charWidth, 8, 270, 180);
-                x2 -= av.charWidth / 2;
-              }
+              case 'S': // Stem case for RNA secondary structure
+                drawStemAnnot(g, row, lastSSX, x, y, iconOffset, startRes,
+                        column, validRes, validEnd);
+                break;
 
-              g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
-              break;
+              default:
+                g.setColor(Color.gray);
+                g.fillRect(lastSSX, y + 6 + iconOffset, (x * av.charWidth)
+                        - lastSSX, 2);
 
-            case 'E':
-              g.setColor(SHEET_COLOUR);
-              g.fillRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
-                      - lastSSX - 4, 7);
-              g.fillPolygon(new int[]
-              { (x * av.charWidth) - 4, (x * av.charWidth) - 4,
-                  (x * av.charWidth) }, new int[]
-              { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
-                      3);
-
-              break;
-
-            case 'S': // Stem case for RNA secondary structure
-              g.setColor(STEM_COLOUR); // row.annotations[column].colour for By
-                                       // RNA Helices colouring
-              // System.out.println("last SSX displayx" +
-              // row.annotations[column-1].displayCharacter +"x");
-              Regex closeparen = new Regex("(\\))");
-              
-              //If a closing base pair half of the stem, display a backward arrow
-              if (closeparen
-                      .search(row.annotations[column - 1].displayCharacter))// row.annotations[column-1].displayCharacter))
-              {
-                g.fillPolygon(new int[]
-                { lastSSX + 5, lastSSX + 5, lastSSX },
-                        new int[]
-                        { y + iconOffset, y + 14 + iconOffset,
-                            y + 8 + iconOffset }, 3);
-                g.fillRect(lastSSX + 2, y + 4 + iconOffset,
-                        (x * av.charWidth) - lastSSX - 2, 7);
-              }
-              else //display a forward arrow
-              {
-                g.fillRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
-                        - lastSSX - 4, 7);
-                g.fillPolygon(new int[]
-                { (x * av.charWidth) - 5, (x * av.charWidth) - 5,
-                    (x * av.charWidth) },
-                        new int[]
-                        { y + iconOffset, y + 14 + iconOffset,
-                            y + 8 + iconOffset }, 3);
+                break;
               }
-              break;
-
-            default:
-              g.setColor(Color.gray);
-              g.fillRect(lastSSX, y + 6 + iconOffset, (x * av.charWidth)
-                      - lastSSX, 2);
-
-              break;
             }
-
             if (validRes)
             {
               lastSS = row.annotations[column].secondaryStructure;
@@ -1152,8 +1095,10 @@ public class AnnotationPanel extends JPanel implements MouseListener,
             {
               lastSS = ' ';
             }
-
-            lastSSX = (x * av.charWidth);
+            if (x > -1)
+            {
+              lastSSX = (x * av.charWidth);
+            }
           }
         }
 
@@ -1178,64 +1123,21 @@ public class AnnotationPanel extends JPanel implements MouseListener,
         switch (lastSS)
         {
         case 'H':
-          g.setColor(HELIX_COLOUR);
-          if (MAC)
-          {
-            // Off by 1 offset when drawing rects and ovals
-            // to offscreen image on the MAC
-            g.fillRoundRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
-                    - lastSSX, 7, 8, 8);
-            break;
-          }
-
-          int sCol = (lastSSX / av.charWidth) + startRes;
-          int x1 = lastSSX;
-          int x2 = (x * av.charWidth);
-
-          if (sCol == 0 || row.annotations[sCol - 1] == null
-                  || row.annotations[sCol - 1].secondaryStructure != 'H')
-          {
-            g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90, 180);
-            x1 += av.charWidth / 2;
-          }
-
-          if (row.annotations[column] == null
-                  || row.annotations[column].secondaryStructure != 'H')
-          {
-            g.fillArc((x * av.charWidth) - av.charWidth,
-                    y + 4 + iconOffset, av.charWidth, 8, 270, 180);
-            x2 -= av.charWidth / 2;
-          }
-
-          g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
-
+          drawHelixAnnot(g, row, lastSSX, x, y, iconOffset, startRes,
+                  column, validRes, validEnd);
           break;
 
         case 'E':
-          g.setColor(SHEET_COLOUR);
-
-          if (!validEnd || row.annotations[endRes] == null
-                  || row.annotations[endRes].secondaryStructure != 'E')
-          {
-            g.fillRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
-                    - lastSSX - 4, 7);
-            g.fillPolygon(new int[]
-            { (x * av.charWidth) - 4, (x * av.charWidth) - 4,
-                (x * av.charWidth) }, new int[]
-            { y + iconOffset, y + 14 + iconOffset, y + 7 + iconOffset }, 3);
-          }
-          else
-          {
-            g.fillRect(lastSSX, y + 4 + iconOffset, (x + 1) * av.charWidth
-                    - lastSSX, 7);
-          }
+          drawSheetAnnot(g, row, lastSSX, x, y, iconOffset, startRes,
+                  column, validRes, validEnd);
+          break;
+        case 'S': // Stem case for RNA secondary structure
+          drawStemAnnot(g, row, lastSSX, x, y, iconOffset, startRes,
+                  column, validRes, validEnd);
           break;
-
         default:
-          g.setColor(Color.gray);
-          g.fillRect(lastSSX, y + 6 + iconOffset, (x * av.charWidth)
-                  - lastSSX, 2);
-
+          drawGlyphLine(g, row, lastSSX, x, y, iconOffset, startRes,
+                  column, validRes, validEnd);
           break;
         }
       }
@@ -1305,7 +1207,137 @@ public class AnnotationPanel extends JPanel implements MouseListener,
     }
   }
 
-  public void drawLineGraph(Graphics g, AlignmentAnnotation aa, int sRes,
+  private void drawStemAnnot(Graphics g, AlignmentAnnotation row,
+          int lastSSX, int x, int y, int iconOffset, int startRes,
+          int column, boolean validRes, boolean validEnd)
+  {
+    g.setColor(STEM_COLOUR); 
+    int sCol = (lastSSX / av.charWidth) + startRes;
+    int x1 = lastSSX;
+    int x2 = (x * av.charWidth);
+    Regex closeparen = new Regex("(\\))");
+
+    String dc="";
+    // If a closing base pair half of the stem, display a backward arrow
+    if (column>0 && closeparen.search(dc=row.annotations[column - 1].displayCharacter))
+    {
+      if (sCol == 0 || row.annotations[sCol - 1] == null
+              || !dc.equals(row.annotations[sCol - 1].displayCharacter))
+      //if (validRes && column>1 && row.annotations[column-2]!=null && dc.equals(row.annotations[column-2].displayCharacter))
+      {      g.fillPolygon(new int[]
+      { lastSSX + 5, lastSSX + 5, lastSSX }, new int[]
+      { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3);
+      x1+=5;
+      }
+    }
+    else
+    {
+      // display a forward arrow
+      if (!validRes  || row.annotations[column] == null
+              || !dc.equals(row.annotations[column].displayCharacter))
+      {
+      g.fillPolygon(
+              new int[]
+              { x2 - 5, x2 - 5,
+                  x2 }, new int[]
+              { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
+              3);
+      x2-=5;
+      }
+    }
+    // draw arrow body
+    g.fillRect(x1, y + 4 + iconOffset, x2-x1, 7);
+  }
+
+  private void drawGlyphLine(Graphics g, AlignmentAnnotation row,
+          int lastSSX, int x, int y, int iconOffset, int startRes,
+          int column, boolean validRes, boolean validEnd)
+  {
+    g.setColor(Color.gray);
+    g.fillRect(lastSSX, y + 6 + iconOffset, (x * av.charWidth) - lastSSX, 2);
+  }
+
+  private void drawSheetAnnot(Graphics g, AlignmentAnnotation row,
+          int lastSSX, int x, int y, int iconOffset, int startRes,
+          int column, boolean validRes, boolean validEnd)
+  {
+    g.setColor(SHEET_COLOUR);
+
+    if (!validEnd || !validRes || row.annotations[column] == null
+            || row.annotations[column].secondaryStructure != 'E')
+    {
+      g.fillRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth) - lastSSX
+              - 4, 7);
+      g.fillPolygon(
+              new int[]
+              { (x * av.charWidth) - 4, (x * av.charWidth) - 4,
+                  (x * av.charWidth) }, new int[]
+              { y + iconOffset, y + 14 + iconOffset, y + 7 + iconOffset },
+              3);
+    }
+    else
+    {
+      g.fillRect(lastSSX, y + 4 + iconOffset, (x + 1) * av.charWidth
+              - lastSSX, 7);
+    }
+
+  }
+
+  private void drawHelixAnnot(Graphics g, AlignmentAnnotation row,
+          int lastSSX, int x, int y, int iconOffset, int startRes,
+          int column, boolean validRes, boolean validEnd)
+  {
+    g.setColor(HELIX_COLOUR);
+
+    int sCol = (lastSSX / av.charWidth) + startRes;
+    int x1 = lastSSX;
+    int x2 = (x * av.charWidth);
+
+    if (MAC)
+    {
+      int ofs=av.charWidth/2;
+      // Off by 1 offset when drawing rects and ovals
+      // to offscreen image on the MAC
+      g.fillRoundRect(lastSSX, y + 4 + iconOffset, x2-x1, 8, 8, 8);
+      if (sCol == 0 || row.annotations[sCol - 1] == null
+              || row.annotations[sCol - 1].secondaryStructure != 'H')
+      {
+      } else {
+//        g.setColor(Color.orange);
+        g.fillRoundRect(lastSSX, y + 4 + iconOffset, x2-x1-ofs+1, 8, 0, 0);
+      }
+      if (!validRes  || row.annotations[column] == null
+              || row.annotations[column].secondaryStructure != 'H')
+      {
+        
+      } else {
+//        g.setColor(Color.magenta);
+        g.fillRoundRect(lastSSX+ofs, y + 4 + iconOffset, x2-x1-ofs+1, 8, 0, 0);
+        
+      }
+      
+      return;
+    }
+
+    if (sCol == 0 || row.annotations[sCol - 1] == null
+            || row.annotations[sCol - 1].secondaryStructure != 'H')
+    {
+      g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90, 180);
+      x1 += av.charWidth / 2;
+    }
+
+    if (!validRes  || row.annotations[column] == null
+            || row.annotations[column].secondaryStructure != 'H')
+    {
+      g.fillArc((x * av.charWidth) - av.charWidth, y + 4 + iconOffset,
+              av.charWidth, 8, 270, 180);
+      x2 -= av.charWidth / 2;
+    }
+
+    g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
+  }
+
+public void drawLineGraph(Graphics g, AlignmentAnnotation aa, int sRes,
           int eRes, int y, float min, float max, int graphHeight)
   {
     if (sRes > aa.annotations.length)