JAL-2388 Unit tests and tidies
[jalview.git] / src / jalview / viewmodel / OverviewDimensions.java
index 17f56c9..b34c85d 100644 (file)
  */
 package jalview.viewmodel;
 
-import jalview.api.AlignViewportI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenSequences;
+
+import java.awt.Graphics;
 
 public class OverviewDimensions
 {
@@ -35,12 +38,6 @@ public class OverviewDimensions
 
   private static final int MAX_SEQ_HEIGHT = 300;
 
-  private AlignViewportI av;
-
-  private float scalew = 1f;
-
-  private float scaleh = 1f;
-
   // width of the overview panel
   private int width;
 
@@ -63,30 +60,38 @@ public class OverviewDimensions
   // height of box
   private int boxHeight = -1;
 
+  // scroll position in viewport corresponding to boxX
   private int scrollCol = -1;
 
+  // scroll position in viewport corresponding to boxY
   private int scrollRow = -1;
 
-  public OverviewDimensions(AlignViewportI avi)
+  /**
+   * Create an OverviewDimensions object
+   * 
+   * @param props
+   *          positional properties of the viewport
+   * @param showAnnotationPanel
+   *          true if the annotation panel is to be shown, false otherwise
+   */
+  public OverviewDimensions(ViewportPositionProps props,
+          boolean showAnnotationPanel)
   {
-    this.av = avi;
-
     // scale the initial size of overviewpanel to shape of alignment
-    float initialScale = (float) av.getAlignment().getWidth()
-            / (float) av.getAlignment().getHeight();
+    float initialScale = (float) props.getAbsoluteAlignmentWidth()
+            / (float) props.getAbsoluteAlignmentHeight();
 
-    // TODO: in applet this was getSequenceConsensusHash()
-    // check if it makes any functional difference
-    if (av.getAlignmentConservationAnnotation() == null)
+    if (!showAnnotationPanel)
     {
       graphHeight = 0;
     }
 
-    if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
+    if (props.getAbsoluteAlignmentWidth() > props
+            .getAbsoluteAlignmentHeight())
     {
       // wider
       width = MAX_WIDTH;
-      sequencesHeight = (int) (MAX_WIDTH / initialScale);
+      sequencesHeight = Math.round(MAX_WIDTH / initialScale);
       if (sequencesHeight < MIN_SEQ_HEIGHT)
       {
         sequencesHeight = MIN_SEQ_HEIGHT;
@@ -95,7 +100,7 @@ public class OverviewDimensions
     else
     {
       // taller
-      width = (int) (MAX_WIDTH * initialScale);
+      width = Math.round(MAX_WIDTH * initialScale);
       sequencesHeight = MAX_SEQ_HEIGHT;
 
       if (width < MIN_WIDTH)
@@ -107,118 +112,169 @@ public class OverviewDimensions
 
   /**
    * Check box dimensions and scroll positions and correct if necessary
+   * 
+   * @param mousex
+   *          x position in overview panel
+   * @param mousey
+   *          y position in overview panel
+   * @param hiddenSeqs
+   *          hidden sequences
+   * @param hiddenCols
+   *          hidden columns
+   * @param props
+   *          viewport position properties
    */
-  public void checkValid()
+  public void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, ColumnSelection hiddenCols,
+          ViewportPositionProps props)
   {
-    if (boxY < 0)
-    {
-      boxY = 0;
-    }
+    int x = mousex;
+    int y = mousey;
 
-    if (boxY > (sequencesHeight - boxHeight))
+    int alwidth = props.getAbsoluteAlignmentWidth();
+    int alheight = props.getAbsoluteAlignmentHeight();
+
+    if (x < 0)
     {
-      boxY = sequencesHeight - boxHeight + 1;
+      x = 0;
     }
 
-    if (boxX < 0)
+    if (y < 0)
     {
-      boxX = 0;
+      y = 0;
     }
 
-    if (boxX > (width - boxWidth))
+    //
+    // Convert x value to residue position
+    //
+
+    // need to determine where scrollCol should be, given x
+    // to do this also need to know width of viewport, and some hidden column
+    // correction
+
+    // convert x to residues - this is an absolute position
+    int xAsRes = Math.round((float) x * alwidth / width);
+
+    // get viewport width in residues
+    int vpwidth = props.getEndRes() - props.getStartRes() + 1;
+
+    // get where x should be when accounting for hidden cols
+    // if x is in a hidden col region, shift to left - but we still need
+    // absolute position
+    // so convert back after getting visible region position
+    int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
+
+    // check in case we went off the edge of the alignment
+    int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1);
+    if (visXAsRes + vpwidth - 1 > visAlignWidth)
     {
-      if (av.hasHiddenColumns())
+      // went past the end of the alignment, adjust backwards
+
+      // if last position was before the end of the alignment, need to update
+      if ((scrollCol + vpwidth - 1) < visAlignWidth)
       {
-        // Try smallest possible box
-        boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1)
-                * av.getCharWidth() * scalew);
+        visXAsRes = hiddenCols.findColumnPosition(hiddenCols
+                .findColumnNToLeft(vpwidth - 1, alwidth - 1));
+      }
+      else
+      {
+        visXAsRes = scrollCol;
       }
-      boxX = width - boxWidth;
     }
 
-    scrollCol = (int) (boxX / scalew / av.getCharWidth());
-    scrollRow = (int) (boxY / scaleh / av.getCharHeight());
+    //
+    // Convert y value to sequence position
+    //
+
+    // convert y to residues
+    int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
 
-    if (av.hasHiddenColumns())
+    // get viewport height in sequences
+    // add 1 because height includes both endSeq and startSeq
+    int vpheight = props.getEndSeq() - props.getStartSeq() + 1;
+
+    // get where y should be when accounting for hidden rows
+    // if y is in a hidden row region, shift up - but we still need absolute
+    // position,
+    // so convert back after getting visible region position
+    yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs
+            .findIndexWithoutHiddenSeqs(yAsSeq));
+
+    // check in case we went off the edge of the alignment
+    int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight);
+    int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
+    if (visYAsRes + vpheight - 1 > visAlignHeight)
     {
-      if (!av.getColumnSelection().isVisible(scrollCol))
+      // went past the end of the alignment, adjust backwards
+      if ((scrollRow + vpheight - 1) < visAlignHeight)
       {
-        return;
+        visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs
+                .findIndexNAboveRow(vpheight - 1, alheight - 1));
+      }
+      else
+      {
+        visYAsRes = scrollRow;
       }
-
-      scrollCol = av.getColumnSelection().findColumnPosition(scrollCol);
     }
 
-    if (av.hasHiddenRows())
-    {
-      scrollRow = av.getAlignment().getHiddenSequences()
-              .findIndexWithoutHiddenSeqs(scrollRow);
-    }
+    // update scroll values
+    scrollCol = visXAsRes;
+    scrollRow = visYAsRes;
+
   }
 
   /**
    * Update the overview panel box when the associated alignment panel is
    * changed
    * 
+   * @param hiddenSeqs
+   *          hidden sequences
+   * @param hiddenCols
+   *          hidden columns
+   * @param props
+   *          viewport position properties
    */
-  public void setBoxPosition()
+  public void setBoxPosition(HiddenSequences hiddenSeqs,
+          ColumnSelection hiddenCols, ViewportPositionProps props)
   {
-    updateScales();
-
-    int startRes = av.getStartRes();
-    int endRes = av.getEndRes();
-
-    if (av.hasHiddenColumns())
-    {
-      startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
-      endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
-    }
-
-    int startSeq = av.getStartSeq();
-    int endSeq = av.getEndSeq();
-
-    if (av.hasHiddenRows())
-    {
-      startSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(startSeq);
-
-      endSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(endSeq);
-
-    }
-
-    boxX = (int) (startRes * av.getCharWidth() * scalew);
-    boxY = (int) (startSeq * av.getCharHeight() * scaleh);
-
-    if (av.hasHiddenColumns())
-    {
-      boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
-    }
-    else
-    {
-      boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
-    }
-
-    boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
+    int alwidth = props.getAbsoluteAlignmentWidth();
+    int alheight = props.getAbsoluteAlignmentHeight();
+
+    // work with absolute values of startRes and endRes
+    int startRes = hiddenCols.adjustForHiddenColumns(props.getStartRes());
+    int endRes = hiddenCols.adjustForHiddenColumns(props.getEndRes());
+
+    // work with absolute values of startSeq and endSeq
+    int startSeq = hiddenSeqs.adjustForHiddenSeqs(props.getStartSeq());
+    int endSeq = hiddenSeqs.adjustForHiddenSeqs(props.getEndSeq());
+
+    // boxX, boxY is the x,y location equivalent to startRes, startSeq
+    boxX = Math.round((float) startRes * width / alwidth);
+    boxY = Math.round((float) startSeq * sequencesHeight / alheight);
+
+    // boxWidth is the width in residues translated to pixels
+    // since the box includes both the start and end residues, add 1 to the
+    // difference
+    boxWidth = Math
+            .round((float) (endRes - startRes + 1) * width / alwidth);
+    // boxHeight is the height in sequences translated to pixels
+    boxHeight = Math.round((float) (endSeq - startSeq + 1)
+            * sequencesHeight
+            / alheight);
   }
 
   /**
-   * Update width and height scales in terms of the alignment width and height
+   * Draw the overview panel's viewport box on a graphics object
+   * 
+   * @param g
+   *          the graphics object to draw on
    */
-  public void updateScales()
+  public void drawBox(Graphics g)
   {
-    int alwidth = av.getAlignment().getWidth();
-    int alheight = av.getAlignment().getHeight()
-            + av.getAlignment().getHiddenSequences().getSize();
-
-    int fullsizeWidth = alwidth * av.getCharWidth();
-    int fullsizeHeight = alheight * av.getCharHeight();
-
-    scalew = (float) width / fullsizeWidth;
-    scaleh = (float) sequencesHeight / fullsizeHeight;
+    g.drawRect(boxX, boxY, boxWidth, boxHeight);
+    g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
   }
 
-  // don't like this, scroll vals are separate from setting code
   public int getScrollCol()
   {
     return scrollCol;
@@ -229,36 +285,32 @@ public class OverviewDimensions
     return scrollRow;
   }
 
+  // TODO should be removed, when unit test has mock Graphics object available
+  // to check boxX/boxY
   public int getBoxX()
   {
     return boxX;
   }
 
+  // TODO should be removed, when unit test has mock Graphics object available
+  // to check boxX/boxY
   public int getBoxY()
   {
     return boxY;
   }
 
+  // TODO should be removed, when unit test has mock Graphics object available
   public int getBoxWidth()
   {
     return boxWidth;
   }
 
+  // TODO should be removed, when unit test has mock Graphics object available
   public int getBoxHeight()
   {
     return boxHeight;
   }
 
-  public void setBoxX(int x)
-  {
-    boxX = x;
-  }
-
-  public void setBoxY(int y)
-  {
-    boxY = y;
-  }
-
   public void setWidth(int w)
   {
     width = w;