JAL-3148 SequenceRenderer, ResidueColourFinder overloads and
[jalview.git] / src / jalview / gui / SequenceRenderer.java
index 4498f88..90d068b 100755 (executable)
@@ -23,35 +23,30 @@ package jalview.gui;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
-import jalview.renderer.ResidueShaderI;
+import jalview.renderer.ResidueColourFinder;
 import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.schemes.ColourSchemeI;
 import jalview.util.Comparison;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 
-public class SequenceRenderer implements jalview.api.SequenceRenderer
+public class SequenceRenderer implements jalview.api.SequenceRendererI
 {
   final static int CHAR_TO_UPPER = 'A' - 'a';
 
-  AlignViewportI av;
+  private AlignViewportI av;
 
-  FontMetrics fm;
+  private FontMetrics fm;
 
-  boolean renderGaps = true;
+  private SequenceGroup[] allGroups = null;
 
-  SequenceGroup currentSequenceGroup = null;
+  private Graphics graphics;
 
-  SequenceGroup[] allGroups = null;
+  private boolean monospacedFont;
 
-  Color resBoxColour;
-
-  Graphics graphics;
-
-  boolean monospacedFont;
-
-  boolean forOverview = false;
+  private ResidueColourFinder resColourFinder;
 
   /**
    * Creates a new SequenceRenderer object
@@ -61,15 +56,27 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   public SequenceRenderer(AlignViewportI viewport)
   {
     this.av = viewport;
+    resColourFinder = new ResidueColourFinder();
   }
 
   /**
-   * DOCUMENT ME!
+   * Constructor given a choice of colour scheme. May be used to find colours
+   * for a structure that has a viewport colour scheme other than 'by sequence'
    * 
-   * @param b
-   *          DOCUMENT ME!
+   * @param cs
    */
-  public void prepare(Graphics g, boolean renderGaps)
+  public SequenceRenderer(AlignViewportI viewport, ColourSchemeI cs) 
+  {
+    this.av = viewport;
+    resColourFinder = new ResidueColourFinder(viewport, cs);
+  }
+
+/**
+   * Sets the Graphics context to draw on, and also guesses whether we are using a monospaced font
+   * 
+   * @param g
+   */
+  public void setGraphics(Graphics g)
   {
     graphics = g;
     fm = g.getFontMetrics();
@@ -79,28 +86,6 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
     monospacedFont = (dwidth == fm.getStringBounds("|", g).getWidth()
             && av.getCharWidth() == dwidth);
-
-    this.renderGaps = renderGaps;
-  }
-
-  protected Color getResidueBoxColour(SequenceI seq, int i)
-  {
-    // rate limiting step when rendering overview for lots of groups
-    allGroups = av.getAlignment().findAllGroups(seq);
-
-    if (inCurrentSequenceGroup(i))
-    {
-      if (currentSequenceGroup.getDisplayBoxes())
-      {
-        getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq, i);
-      }
-    }
-    else if (av.getShowBoxes())
-    {
-      getBoxColour(av.getResidueShading(), seq, i);
-    }
-
-    return resBoxColour;
   }
 
   /**
@@ -117,65 +102,27 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   public Color getResidueColour(final SequenceI seq, int position,
           FeatureColourFinder finder)
   {
-    Color col = getResidueBoxColour(seq, position);
-
-    if (finder != null)
-    {
-      col = finder.findFeatureColour(col, seq, position);
-    }
-    return col;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param shader
-   *          DOCUMENT ME!
-   * @param seq
-   *          DOCUMENT ME!
-   * @param i
-   *          DOCUMENT ME!
-   */
-  void getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
-  {
-    if (shader.getColourScheme() != null)
-    {
-      resBoxColour = shader.findColour(seq.getCharAt(i), i, seq);
-    }
-    else if (forOverview && !Comparison.isGap(seq.getCharAt(i)))
-    {
-      resBoxColour = Color.lightGray;
-    }
-    else
-    {
-      resBoxColour = Color.white;
-    }
+    allGroups = av.getAlignment().findAllGroups(seq);
+    return resColourFinder.getResidueColour(av.getShowBoxes(),
+            av.getResidueShading(),
+            allGroups, seq, position,
+            finder);
   }
 
   /**
-   * DOCUMENT ME!
+   * Draws the sequence (box colour and residues) over the given range, at the
+   * specified y-offset on the Graphics context
    * 
-   * @param g
-   *          DOCUMENT ME!
    * @param seq
-   *          DOCUMENT ME!
-   * @param sg
-   *          DOCUMENT ME!
+   * @param sg  groups (if any) that the sequence is a member of (may have
+   *            distinct group colouring)
    * @param start
-   *          DOCUMENT ME!
    * @param end
-   *          DOCUMENT ME!
-   * @param x1
-   *          DOCUMENT ME!
    * @param y1
-   *          DOCUMENT ME!
-   * @param width
-   *          DOCUMENT ME!
-   * @param height
-   *          DOCUMENT ME!
+   * @param drawGaps
    */
   public void drawSequence(SequenceI seq, SequenceGroup[] sg, int start,
-          int end, int y1)
+          int end, int y1, boolean drawGaps)
   {
     allGroups = sg;
 
@@ -183,31 +130,24 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
     if (av.isValidCharWidth())
     {
-      drawText(seq, start, end, y1);
+      drawText(seq, start, end, y1, drawGaps);
     }
   }
 
   /**
-   * DOCUMENT ME!
+   * Draws box colours on the given sequence residue range, at the specified
+   * y-offset on the Graphics context
    * 
    * @param seq
-   *          DOCUMENT ME!
    * @param start
-   *          DOCUMENT ME!
    * @param end
-   *          DOCUMENT ME!
-   * @param x1
-   *          DOCUMENT ME!
    * @param y1
-   *          DOCUMENT ME!
-   * @param width
-   *          DOCUMENT ME!
-   * @param height
-   *          DOCUMENT ME!
    */
   public synchronized void drawBoxes(SequenceI seq, int start, int end,
           int y1)
   {
+    Color resBoxColour = Color.white;
+
     if (seq == null)
     {
       return; // fix for racecondition
@@ -227,17 +167,22 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
       if (i < length)
       {
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(
+                allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (currentSequenceGroup.getDisplayBoxes())
           {
-            getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq,
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq,
                     i);
           }
         }
         else if (av.getShowBoxes())
         {
-          getBoxColour(av.getResidueShading(), seq, i);
+          resBoxColour = resColourFinder
+                  .getBoxColour(av.getResidueShading(), seq, i);
         }
       }
 
@@ -268,24 +213,16 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   }
 
   /**
-   * DOCUMENT ME!
+   * Draws residue letters on the given sequence residue range, at the specified
+   * y-offset on the Graphics context
    * 
    * @param seq
-   *          DOCUMENT ME!
    * @param start
-   *          DOCUMENT ME!
    * @param end
-   *          DOCUMENT ME!
-   * @param x1
-   *          DOCUMENT ME!
    * @param y1
-   *          DOCUMENT ME!
-   * @param width
-   *          DOCUMENT ME!
-   * @param height
-   *          DOCUMENT ME!
+   * @param drawGaps
    */
-  public void drawText(SequenceI seq, int start, int end, int y1)
+  public void drawText(SequenceI seq, int start, int end, int y1, boolean drawGaps)
   {
     y1 += av.getCharHeight() - av.getCharHeight() / 5; // height/5 replaces pady
     int charOffset = 0;
@@ -317,10 +254,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
       boolean srep = av.isDisplayReferenceSeq();
       boolean getboxColour = false;
       boolean isarep = av.getAlignment().getSeqrep() == seq;
-      boolean isgrep = currentSequenceGroup != null
-              ? currentSequenceGroup.getSeqrep() == seq
-              : false;
-      char sr_c;
+      Color resBoxColour = Color.white;
+
       for (int i = start; i <= end; i++)
       {
 
@@ -328,12 +263,15 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
         getboxColour = false;
         s = seq.getCharAt(i);
 
-        if (!renderGaps && jalview.util.Comparison.isGap(s))
+        if (!drawGaps && Comparison.isGap(s))
         {
           continue;
         }
 
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(
+                allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (!currentSequenceGroup.getDisplayText())
           {
@@ -344,7 +282,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
                   || currentSequenceGroup.getColourText())
           {
             getboxColour = true;
-            getBoxColour(currentSequenceGroup.getGroupColourScheme(), seq,
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq,
                     i);
 
             if (currentSequenceGroup.getColourText())
@@ -366,15 +305,15 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           {
             graphics.setColor(currentSequenceGroup.textColour);
           }
+          boolean isgrep = currentSequenceGroup != null
+                  ? currentSequenceGroup.getSeqrep() == seq : false;
           if (!isarep && !isgrep
                   && currentSequenceGroup.getShowNonconserved()) // todo
                                                                  // optimize
           {
             // todo - use sequence group consensus
             s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
-
           }
-
         }
         else
         {
@@ -386,7 +325,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           if (av.getColourText())
           {
             getboxColour = true;
-            getBoxColour(av.getResidueShading(), seq, i);
+            resBoxColour = resColourFinder
+                    .getBoxColour(av.getResidueShading(), seq, i);
 
             if (av.getShowBoxes())
             {
@@ -402,7 +342,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           {
             if (!getboxColour)
             {
-              getBoxColour(av.getResidueShading(), seq, i);
+              resBoxColour = resColourFinder
+                      .getBoxColour(av.getResidueShading(), seq, i);
             }
 
             if (resBoxColour.getRed() + resBoxColour.getBlue()
@@ -414,15 +355,12 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           if (!isarep && av.getShowUnconserved())
           {
             s = getDisplayChar(srep, i, s, '.', null);
-
           }
-
         }
 
         charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
         graphics.drawString(String.valueOf(s),
                 charOffset + av.getCharWidth() * (i - start), y1);
-
       }
     }
   }
@@ -473,35 +411,6 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   /**
    * DOCUMENT ME!
    * 
-   * @param res
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  boolean inCurrentSequenceGroup(int res)
-  {
-    if (allGroups == null)
-    {
-      return false;
-    }
-
-    for (int i = 0; i < allGroups.length; i++)
-    {
-      if ((allGroups[i].getStartRes() <= res)
-              && (allGroups[i].getEndRes() >= res))
-      {
-        currentSequenceGroup = allGroups[i];
-
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
    * @param seq
    *          DOCUMENT ME!
    * @param start
@@ -547,21 +456,30 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     }
   }
 
-  public void drawCursor(SequenceI seq, int res, int x1, int y1)
+  /**
+   * Draw a sequence canvas cursor
+   * 
+   * @param g
+   *          graphics context to draw on
+   * @param s
+   *          character to draw at cursor
+   * @param x1
+   *          x position of cursor in graphics context
+   * @param y1
+   *          y position of cursor in graphics context
+   */
+  public void drawCursor(Graphics g, char s, int x1, int y1)
   {
     int pady = av.getCharHeight() / 5;
     int charOffset = 0;
-    graphics.setColor(Color.black);
-    graphics.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
+    g.setColor(Color.black);
+    g.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
 
     if (av.isValidCharWidth())
     {
-      graphics.setColor(Color.white);
-
-      char s = seq.getCharAt(res);
-
+      g.setColor(Color.white);
       charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
-      graphics.drawString(String.valueOf(s), charOffset + x1,
+      g.drawString(String.valueOf(s), charOffset + x1,
               (y1 + av.getCharHeight()) - pady);
     }