JAL-3626 from JAL-3253-applet web page embedding
[jalview.git] / src / jalview / viewmodel / OverviewDimensions.java
index 4af4175..c153dc1 100644 (file)
  */
 package jalview.viewmodel;
 
-import jalview.datamodel.ColumnSelection;
+import jalview.api.AlignmentColsCollectionI;
+import jalview.api.AlignmentRowsCollectionI;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
 
+import java.awt.Dimension;
 import java.awt.Graphics;
 
-public class OverviewDimensions
+public abstract class OverviewDimensions
 {
-  // Default width and height values
-  private static final int DEFAULT_GRAPH_HEIGHT = 20;
+  protected static final int MAX_WIDTH = 400;
+
+  protected static final int MIN_WIDTH = 120;
 
-  private static final int MAX_WIDTH = 400;
+  protected static final int MIN_SEQ_HEIGHT = 40;
 
-  private static final int MIN_WIDTH = 120;
+  protected static final int MAX_SEQ_HEIGHT = 300;
 
-  private static final int MIN_SEQ_HEIGHT = 40;
+  private static final int DEFAULT_GRAPH_HEIGHT = 20;
 
-  private static final int MAX_SEQ_HEIGHT = 300;
+  protected int width;
 
-  // width of the overview panel
-  private int width;
+  protected int sequencesHeight;
 
-  // height of sequences part of the overview panel
-  private int sequencesHeight;
+  protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
 
-  // height of the graphs part of the overview panel
-  private int graphHeight = DEFAULT_GRAPH_HEIGHT;
+  protected int boxX = -1;
 
-  // dimensions of box outlining current extent of view in alignment panel
-  // location of left side of box
-  private int boxX = -1;
+  protected int boxY = -1;
 
-  // location of bottom of box
-  private int boxY = -1;
+  protected int boxWidth = -1;
 
-  // width of box
-  private int boxWidth = -1;
+  protected int boxHeight = -1;
 
-  // height of box
-  private int boxHeight = -1;
+  protected int alwidth;
 
-  // scroll position in viewport corresponding to boxX
-  private int scrollCol = -1;
+  protected int alheight;
 
-  // scroll position in viewport corresponding to boxY
-  private int scrollRow = -1;
+  protected float widthRatio;
+
+  protected float heightRatio;
 
   /**
    * Create an OverviewDimensions object
    * 
-   * @param props
+   * @param ranges
    *          positional properties of the viewport
    * @param showAnnotationPanel
    *          true if the annotation panel is to be shown, false otherwise
    */
-  public OverviewDimensions(ViewportPositionProps props,
-          boolean showAnnotationPanel)
+  public OverviewDimensions(ViewportRanges ranges,
+          boolean showAnnotationPanel, Dimension dim)
   {
-    // scale the initial size of overviewpanel to shape of alignment
-    float initialScale = (float) props.getAbsoluteAlignmentWidth()
-            / (float) props.getAbsoluteAlignmentHeight();
-
     if (!showAnnotationPanel)
     {
       graphHeight = 0;
     }
 
-    if (props.getAbsoluteAlignmentWidth() > props
+    // scale the initial size of overviewpanel to shape of alignment
+    float initialScale = (float) ranges.getAbsoluteAlignmentWidth()
+            / (float) ranges.getAbsoluteAlignmentHeight();
+
+    if (dim != null)
+    {
+      width = dim.width;
+      sequencesHeight = dim.height;
+      return;
+    }
+
+    if (ranges.getAbsoluteAlignmentWidth() > ranges
             .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;
@@ -100,7 +104,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)
@@ -111,155 +115,6 @@ 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 updateViewportFromMouse(int mousex, int mousey,
-          HiddenSequences hiddenSeqs, ColumnSelection hiddenCols,
-          ViewportPositionProps props)
-  {
-    int x = mousex;
-    int y = mousey;
-
-    int alwidth = props.getAbsoluteAlignmentWidth();
-    int alheight = props.getAbsoluteAlignmentHeight();
-
-    if (x < 0)
-    {
-      x = 0;
-    }
-
-    if (y < 0)
-    {
-      y = 0;
-    }
-
-    //
-    // 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
-    xAsRes = hiddenCols.adjustForHiddenColumns(hiddenCols
-            .findColumnPosition(xAsRes));
-
-    // get where end res should be by adding the viewport width on
-    // subtract 1 because the width includes endRes
-    int endRes = xAsRes + vpwidth - 1;
-
-    // check in case we went off the edge of the alignment
-    int visAlignWidth = hiddenCols.findColumnPosition(alwidth);
-    if (endRes > visAlignWidth - 1)
-    {
-      // went past the end of the alignment, adjust backwards
-      endRes = visAlignWidth - 1;
-      // recalc xAsRes backwards from endRes
-      // add 1 because width includes xAsRes
-      xAsRes = hiddenCols.adjustForHiddenColumns(endRes - vpwidth + 1);
-    }
-
-    //
-    // Convert y value to sequence position
-    //
-
-    // convert y to residues
-    int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
-
-    // 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));
-
-    // get where end seq should be by adding the viewport height on
-    int endSeq = yAsSeq + vpheight - 1;
-
-    // check in case we went off the edge of the alignment
-    int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight);
-    if (hiddenSeqs.findIndexWithoutHiddenSeqs(endSeq) > visAlignHeight - 1)
-    {
-      // went past the end of the alignment, adjust backwards
-      endSeq = visAlignHeight - 1;
-      // recalc yAsSeq backwards from endSeq
-      yAsSeq = endSeq - vpheight + 1;
-    }
-
-    // convert absolute positions back to visible alignment positions for
-    // viewport scrolling
-    scrollCol = hiddenCols.findColumnPosition(xAsRes);
-    scrollRow = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
-  }
-
-  /**
-   * 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(HiddenSequences hiddenSeqs,
-          ColumnSelection hiddenCols, ViewportPositionProps props)
-  {
-    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
-    // since the box includes both the start and end sequences, add 1 to the
-    // difference
-    boxHeight = Math.round((float) (endSeq - startSeq + 1)
-            * sequencesHeight
-            / alheight);
-  }
-
-  /**
    * Draw the overview panel's viewport box on a graphics object
    * 
    * @param g
@@ -271,53 +126,26 @@ public class OverviewDimensions
     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;
-  }
-
-  public int getScrollRow()
-  {
-    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 setWidth(int w)
-  {
-    width = w;
-  }
-
-  public void setHeight(int h)
-  {
-    sequencesHeight = h - graphHeight;
-  }
-
   public int getWidth()
   {
     return width;
@@ -337,4 +165,163 @@ public class OverviewDimensions
   {
     return graphHeight;
   }
-}
+
+  public float getPixelsPerCol()
+  {
+    resetAlignmentDims();
+    return 1 / widthRatio;
+  }
+
+  public float getPixelsPerSeq()
+  {
+    resetAlignmentDims();
+    return 1 / heightRatio;
+  }
+
+  public void setWidth(int w)
+  {
+    width = w;
+    widthRatio = (float) alwidth / width;
+  }
+
+  public void setHeight(int h)
+  {
+    sequencesHeight = h - graphHeight;
+    heightRatio = (float) alheight / sequencesHeight;
+  }
+
+  /**
+   * Update the viewport location from a mouse click in the overview panel
+   * 
+   * @param mousex
+   *          x location of mouse
+   * @param mousey
+   *          y location of mouse
+   * @param hiddenSeqs
+   *          the alignment's hidden sequences
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   */
+  public abstract void updateViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
+
+  /**
+   * Update the viewport location from a mouse drag within the overview's box
+   * 
+   * @param mousex
+   *          x location of mouse
+   * @param mousey
+   *          y location of mouse
+   * @param hiddenSeqs
+   *          the alignment's hidden sequences
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   */
+  public abstract void adjustViewportFromMouse(int mousex, int mousey,
+          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
+
+  /**
+   * Initialise dragging from the mouse - must be called on initial mouse click
+   * before using adjustViewportFromMouse in drag operations
+   * 
+   * @param mousex
+   *          x location of mouse
+   * @param mousey
+   *          y location of mouse
+   * @param hiddenSeqs
+   *          the alignment's hidden sequences
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   */
+  public abstract void setDragPoint(int x, int y,
+          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
+
+  /*
+   * Move the viewport so that the top left corner of the overview's box 
+   * is at the mouse position (leftx, topy)
+   */
+  protected abstract void updateViewportFromTopLeft(int leftx, int topy,
+          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
+
+  /**
+   * Set the overview panel's box position to match the viewport
+   * 
+   * @param hiddenSeqs
+   *          the alignment's hidden sequences
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   */
+  public abstract void setBoxPosition(HiddenSequences hiddenSeqs,
+          HiddenColumns hiddenCols);
+
+  /**
+   * Get the collection of columns used by this overview dimensions object
+   * 
+   * @param hiddenCols
+   *          the alignment's hidden columns
+   * @return a column collection
+   */
+  public abstract AlignmentColsCollectionI getColumns(AlignmentI al);
+
+  /**
+   * Get the collection of rows used by this overview dimensions object
+   * 
+   * @param al
+   *          the alignment
+   * @return a row collection
+   */
+  public abstract AlignmentRowsCollectionI getRows(AlignmentI al);
+
+  /**
+   * Updates overview dimensions to account for current alignment dimensions
+   */
+  protected abstract void resetAlignmentDims();
+
+  /*
+   * Given the box coordinates in residues and sequences, set the box dimensions in the overview window
+   */
+  protected void setBoxPosition(int startRes, int startSeq, int vpwidth,
+          int vpheight)
+  {
+    resetAlignmentDims();
+
+    // boxX, boxY is the x,y location equivalent to startRes, startSeq
+    int xPos = Math.min(startRes, alwidth - vpwidth + 1);
+    boxX = Math.round(xPos / widthRatio);
+    boxY = Math.round(startSeq / heightRatio);
+
+    // boxWidth is the width in residues translated to pixels
+    boxWidth = Math.round(vpwidth / widthRatio);
+
+    // boxHeight is the height in sequences translated to pixels
+    boxHeight = Math.round(vpheight / heightRatio);
+  }
+
+  /**
+   * Answers if a mouse position is in the overview's red box
+   * 
+   * @param x
+   *          mouse x position
+   * @param y
+   *          mouse y position
+   * @return true if (x,y) is inside the box
+   */
+  public boolean isPositionInBox(int x, int y)
+  {
+    return (x > boxX && y > boxY && x < boxX + boxWidth
+            && y < boxY + boxHeight);
+  }
+
+  /*
+   * Given the centre x position, calculate the box's left x position
+   */
+  protected abstract int getLeftXFromCentreX(int mousex,
+          HiddenColumns hidden);
+
+  /*
+   * Given the centre y position, calculate the box's top y position
+   */
+  protected abstract int getTopYFromCentreY(int mousey,
+          HiddenSequences hidden);
+
+}
\ No newline at end of file