JAL-2388 Corrected overview panel behaviour, updated tests
[jalview.git] / src / jalview / viewmodel / OverviewDimensions.java
index 9b55e55..ed9a155 100644 (file)
@@ -21,6 +21,8 @@
 package jalview.viewmodel;
 
 import jalview.api.AlignViewportI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenSequences;
 
 import java.awt.Graphics;
 
@@ -39,9 +41,7 @@ public class OverviewDimensions
 
   private AlignViewportI av;
 
-  private float scalew = 1f;
-
-  private float scaleh = 1f;
+  private ViewportPositionProps posProps;
 
   // width of the overview panel
   private int width;
@@ -69,22 +69,22 @@ public class OverviewDimensions
 
   private int scrollRow = -1;
 
-  public OverviewDimensions(AlignViewportI avi)
+  public OverviewDimensions(AlignViewportI avi, boolean showAnnotationPanel)
   {
     this.av = avi;
+    this.posProps = av.getPosProps();
 
     // scale the initial size of overviewpanel to shape of alignment
-    float initialScale = (float) av.getAlignment().getWidth()
-            / (float) av.getAlignment().getHeight();
+    float initialScale = (float) posProps.getAlignmentWidthInCols()
+            / (float) posProps.getAlignmentHeightInRows();
 
-    // 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 (posProps.getAlignmentWidthInCols() > posProps
+            .getAlignmentHeightInRows())
     {
       // wider
       width = MAX_WIDTH;
@@ -110,105 +110,125 @@ public class OverviewDimensions
   /**
    * Check box dimensions and scroll positions and correct if necessary
    */
-  public void setBoxPositionByMouse(int x, int y)
+  public void updateViewportFromMouse(int x, int y)
   {
-    boxX = x;
-    boxY = y;
-    if (boxY < 0)
+    int alwidth = av.getAlignment().getWidth();
+    int alheight = av.getAlignment().getAbsoluteHeight();
+
+    HiddenSequences hiddenSeqs = av.getAlignment().getHiddenSequences();
+    ColumnSelection hiddenCols = av.getColumnSelection();
+
+    if (x < 0)
     {
-      boxY = 0;
+      x = 0;
     }
-    else if (boxY > (sequencesHeight - boxHeight))
+    else if (x >= alwidth)
     {
-      boxY = sequencesHeight - boxHeight + 1;
+      x = alwidth - 1;
     }
 
-    if (boxX < 0)
+    if (y < 0)
     {
-      boxX = 0;
+      y = 0;
     }
-    else if (boxX > (width - boxWidth))
+    else if (y >= alheight)
     {
-      if (av.hasHiddenColumns())
-      {
-        // Try smallest possible box
-        boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1)
-                * av.getCharWidth() * scalew);
-      }
-      boxX = width - boxWidth;
+      y = alheight - 1;
     }
 
-    scrollCol = (int) (boxX / scalew / av.getCharWidth());
-    scrollRow = (int) (boxY / scaleh / av.getCharHeight());
+    //
+    // Convert x value to residue position
+    //
 
-    if (av.hasHiddenColumns())
-    {
-      if (!av.getColumnSelection().isVisible(scrollCol))
-      {
-        return;
-      }
+    // need to determine where scrollCol should be, given x
+    // to do this also need to know width of viewport, and some hidden column
+    // correction
 
-      scrollCol = av.getColumnSelection().findColumnPosition(scrollCol);
-    }
+    // convert x to residues - this is an absolute position
+    int xAsRes = Math.round((float) x * alwidth / width);
 
-    if (av.hasHiddenRows())
-    {
-      scrollRow = av.getAlignment().getHiddenSequences()
-              .findIndexWithoutHiddenSeqs(scrollRow);
-    }
-  }
+    // get viewport width in residues
+    int vpwidth = av.getPosProps().getEndRes()
+            - av.getPosProps().getStartRes() + 1;
 
-  /**
-   * Update the overview panel box when the associated alignment panel is
-   * changed
-   * 
-   */
-  public void setBoxPosition()
-  {
-    updateScales();
+    // 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
+    xAsRes = hiddenCols.adjustForHiddenColumns(hiddenCols
+            .findColumnPosition(xAsRes));
 
-    int startRes = av.getStartRes();
-    int endRes = av.getEndRes();
+    // get where end res should be by adding the viewport width on
+    int endRes = xAsRes + vpwidth;
 
-    if (av.hasHiddenColumns())
+    // check in case we went off the edge of the alignment
+    if (endRes > alwidth)
     {
-      startRes = av.getColumnSelection().adjustForHiddenColumns(startRes);
-      endRes = av.getColumnSelection().adjustForHiddenColumns(endRes);
+      // went past the end of the alignment, adjust backwards
+      endRes = alwidth;
+      // recalc xAsRes backwards from endRes
+      xAsRes = endRes - vpwidth;
     }
 
-    int startSeq = av.getStartSeq();
-    int endSeq = av.getEndSeq();
+    //
+    // Convert y value to sequence position
+    //
 
-    if (av.hasHiddenRows())
-    {
-      startSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(startSeq);
+    // convert y to residues
+    int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
 
-      endSeq = av.getAlignment().getHiddenSequences()
-              .adjustForHiddenSeqs(endSeq);
-    }
+    // get viewport height in sequences
+    int vpheight = av.getPosProps().getEndSeq()
+            - av.getPosProps().getStartSeq();
+
+    // 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));
 
-    boxX = (int) (startRes * av.getCharWidth() * scalew);
-    boxY = (int) (startSeq * av.getCharHeight() * scaleh);
+    // get where end seq should be by adding the viewport height on
+    int endSeq = yAsSeq + vpheight;
+
+    // check in case we went off the edge of the alignment
+    if (endSeq > alheight)
+    {
+      // went past the end of the alignment, adjust backwards
+      endSeq = alheight;
+      // recalc yAsSeq backwards from endSeq
+      yAsSeq = endSeq - vpheight;
+    }
 
-    boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
-    boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
+    // convert absolute positions back to visible alignment positions for
+    // viewport scrolling
+    scrollCol = hiddenCols.findColumnPosition(xAsRes);
+    scrollRow = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
   }
 
   /**
-   * Update width and height scales in terms of the alignment width and height
+   * Update the overview panel box when the associated alignment panel is
+   * changed
+   * 
    */
-  public void updateScales()
+  public void setBoxPosition()
   {
     int alwidth = av.getAlignment().getWidth();
-    int alheight = av.getAlignment().getHeight()
-            + av.getAlignment().getHiddenSequences().getSize();
+    int alheight = av.getAlignment().getAbsoluteHeight();
 
-    int fullsizeWidth = alwidth * av.getCharWidth();
-    int fullsizeHeight = alheight * av.getCharHeight();
+    int startRes = av.getPosProps().getAbsoluteStartRes();
+    int endRes = av.getPosProps().getAbsoluteEndRes();
 
-    scalew = (float) width / fullsizeWidth;
-    scaleh = (float) sequencesHeight / fullsizeHeight;
+    int startSeq = av.getPosProps().getAbsoluteStartSeq();
+    int endSeq = av.getPosProps().getAbsoluteEndSeq();
+
+    boxX = Math.round((float) startRes * width / alwidth);
+    boxY = Math.round((float) startSeq * sequencesHeight / alheight);
+
+    boxWidth = Math
+            .round((float) (endRes - startRes + 1) * width / alwidth);
+    boxHeight = Math.round((float) (endSeq - startSeq) * sequencesHeight
+            / alheight);
   }
 
   /**
@@ -248,11 +268,13 @@ public class OverviewDimensions
     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;