JAL-3626 from JAL-3253-applet web page embedding
[jalview.git] / src / jalview / viewmodel / OverviewDimensions.java
index 9b55e55..c153dc1 100644 (file)
  */
 package jalview.viewmodel;
 
-import jalview.api.AlignViewportI;
+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;
-
-  private static final int MAX_WIDTH = 400;
+  protected static final int MAX_WIDTH = 400;
 
-  private static final int MIN_WIDTH = 120;
+  protected static final int MIN_WIDTH = 120;
 
-  private static final int MIN_SEQ_HEIGHT = 40;
+  protected static final int MIN_SEQ_HEIGHT = 40;
 
-  private static final int MAX_SEQ_HEIGHT = 300;
+  protected static final int MAX_SEQ_HEIGHT = 300;
 
-  private AlignViewportI av;
+  private static final int DEFAULT_GRAPH_HEIGHT = 20;
 
-  private float scalew = 1f;
+  protected int width;
 
-  private float scaleh = 1f;
+  protected int sequencesHeight;
 
-  // width of the overview panel
-  private int width;
+  protected int graphHeight = DEFAULT_GRAPH_HEIGHT;
 
-  // height of sequences part of the overview panel
-  private int sequencesHeight;
+  protected int boxX = -1;
 
-  // height of the graphs part of the overview panel
-  private int graphHeight = DEFAULT_GRAPH_HEIGHT;
+  protected int boxY = -1;
 
-  // dimensions of box outlining current extent of view in alignment panel
-  // location of left side of box
-  private int boxX = -1;
+  protected int boxWidth = -1;
 
-  // location of bottom of box
-  private int boxY = -1;
+  protected int boxHeight = -1;
 
-  // width of box
-  private int boxWidth = -1;
+  protected int alwidth;
 
-  // height of box
-  private int boxHeight = -1;
+  protected int alheight;
 
-  private int scrollCol = -1;
+  protected float widthRatio;
 
-  private int scrollRow = -1;
+  protected float heightRatio;
 
-  public OverviewDimensions(AlignViewportI avi)
+  /**
+   * Create an OverviewDimensions object
+   * 
+   * @param ranges
+   *          positional properties of the viewport
+   * @param showAnnotationPanel
+   *          true if the annotation panel is to be shown, false otherwise
+   */
+  public OverviewDimensions(ViewportRanges ranges,
+          boolean showAnnotationPanel, Dimension dim)
   {
-    this.av = avi;
+    if (!showAnnotationPanel)
+    {
+      graphHeight = 0;
+    }
 
     // scale the initial size of overviewpanel to shape of alignment
-    float initialScale = (float) av.getAlignment().getWidth()
-            / (float) av.getAlignment().getHeight();
+    float initialScale = (float) ranges.getAbsoluteAlignmentWidth()
+            / (float) ranges.getAbsoluteAlignmentHeight();
 
-    // TODO: in applet this was getSequenceConsensusHash()
-    // check if it makes any functional difference
-    if (av.getAlignmentConservationAnnotation() == null)
+    if (dim != null)
     {
-      graphHeight = 0;
+      width = dim.width;
+      sequencesHeight = dim.height;
+      return;
     }
 
-    if (av.getAlignment().getWidth() > av.getAlignment().getHeight())
+    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;
@@ -97,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)
@@ -108,110 +115,6 @@ public class OverviewDimensions
   }
 
   /**
-   * Check box dimensions and scroll positions and correct if necessary
-   */
-  public void setBoxPositionByMouse(int x, int y)
-  {
-    boxX = x;
-    boxY = y;
-    if (boxY < 0)
-    {
-      boxY = 0;
-    }
-    else if (boxY > (sequencesHeight - boxHeight))
-    {
-      boxY = sequencesHeight - boxHeight + 1;
-    }
-
-    if (boxX < 0)
-    {
-      boxX = 0;
-    }
-    else if (boxX > (width - boxWidth))
-    {
-      if (av.hasHiddenColumns())
-      {
-        // Try smallest possible box
-        boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1)
-                * av.getCharWidth() * scalew);
-      }
-      boxX = width - boxWidth;
-    }
-
-    scrollCol = (int) (boxX / scalew / av.getCharWidth());
-    scrollRow = (int) (boxY / scaleh / av.getCharHeight());
-
-    if (av.hasHiddenColumns())
-    {
-      if (!av.getColumnSelection().isVisible(scrollCol))
-      {
-        return;
-      }
-
-      scrollCol = av.getColumnSelection().findColumnPosition(scrollCol);
-    }
-
-    if (av.hasHiddenRows())
-    {
-      scrollRow = av.getAlignment().getHiddenSequences()
-              .findIndexWithoutHiddenSeqs(scrollRow);
-    }
-  }
-
-  /**
-   * Update the overview panel box when the associated alignment panel is
-   * changed
-   * 
-   */
-  public void setBoxPosition()
-  {
-    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);
-
-    boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew);
-    boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh);
-  }
-
-  /**
-   * Update width and height scales in terms of the alignment width and height
-   */
-  public void updateScales()
-  {
-    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;
-  }
-
-  /**
    * Draw the overview panel's viewport box on a graphics object
    * 
    * @param g
@@ -223,26 +126,11 @@ 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;
@@ -258,43 +146,182 @@ public class OverviewDimensions
     return boxHeight;
   }
 
-  public void setBoxX(int x)
+  public int getWidth()
   {
-    boxX = x;
+    return width;
   }
 
-  public void setBoxY(int y)
+  public int getHeight()
   {
-    boxY = y;
+    return sequencesHeight + graphHeight;
   }
 
-  public void setWidth(int w)
+  public int getSequencesHeight()
   {
-    width = w;
+    return sequencesHeight;
   }
 
-  public void setHeight(int h)
+  public int getGraphHeight()
   {
-    sequencesHeight = h - graphHeight;
+    return graphHeight;
   }
 
-  public int getWidth()
+  public float getPixelsPerCol()
   {
-    return width;
+    resetAlignmentDims();
+    return 1 / widthRatio;
   }
 
-  public int getHeight()
+  public float getPixelsPerSeq()
   {
-    return sequencesHeight + graphHeight;
+    resetAlignmentDims();
+    return 1 / heightRatio;
   }
 
-  public int getSequencesHeight()
+  public void setWidth(int w)
   {
-    return sequencesHeight;
+    width = w;
+    widthRatio = (float) alwidth / width;
   }
 
-  public int getGraphHeight()
+  public void setHeight(int h)
   {
-    return graphHeight;
+    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