JAL-2349 JAL-3855 - interactive point-wise row/column selection, and first attempt...
authorJim Procter <j.procter@dundee.ac.uk>
Thu, 20 Oct 2022 09:08:39 +0000 (10:08 +0100)
committerJim Procter <j.procter@dundee.ac.uk>
Thu, 20 Oct 2022 09:08:39 +0000 (10:08 +0100)
src/jalview/gui/AnnotationPanel.java
src/jalview/gui/SeqPanel.java

index d80c749..ba02a3f 100755 (executable)
@@ -82,7 +82,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 {
   enum DragMode
   {
-    Select, Resize, Undefined
+    Select, Resize, Undefined, MatrixSelect
   };
 
   String HELIX = MessageManager.getString("label.helix");
@@ -132,6 +132,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
   int mouseDragLastY = -1;
 
+  int firstDragX = -1;
+
+  int firstDragY = -1;
+
   DragMode dragMode = DragMode.Undefined;
 
   boolean mouseDragging = false;
@@ -539,8 +543,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
      */
     int height = 0;
     activeRow = -1;
-
+    int yOffset = 0;
+    // todo could reuse getRowIndexAndOffset ?
     final int y = evt.getY();
+
     for (int i = 0; i < aa.length; i++)
     {
       if (aa[i].visible)
@@ -560,6 +566,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
            * we have clicked on a resizable graph annotation
            */
           graphStretch = i;
+          yOffset = height - y;
         }
         break;
       }
@@ -575,7 +582,34 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    ap.getScalePanel().mousePressed(evt);
+    if (graphStretch != -1)
+    {
+      if (aa[graphStretch].graph == AlignmentAnnotation.CUSTOMRENDERER)
+      {
+        int currentX = getColumnForXPos(evt.getX());
+        ContactListI forCurrentX = av.getContactList(aa[graphStretch],
+                currentX);
+        if (forCurrentX != null)
+        {
+          ContactGeometry cXcgeom = new ContactGeometry(forCurrentX,
+                  aa[graphStretch].graphHeight);
+          ContactGeometry.contactInterval cXci = cXcgeom.mapFor(yOffset,
+                  yOffset);
+          int fr, to;
+          fr = Math.min(cXci.cStart, cXci.cEnd);
+          to = Math.max(cXci.cStart, cXci.cEnd);
+          for (int c = fr; c <= to; c++)
+          {
+            av.getColumnSelection().addElement(c);
+          }
+          av.getColumnSelection().addElement(currentX);
+        }
+      }
+    }
+    else
+    {
+      ap.getScalePanel().mousePressed(evt);
+    }
   }
 
   /**
@@ -635,6 +669,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   @Override
   public void mouseReleased(MouseEvent evt)
   {
+    if (dragMode == DragMode.MatrixSelect)
+    {
+      matrixSelectRange(evt);
+    }
     graphStretch = -1;
     mouseDragLastX = -1;
     mouseDragLastY = -1;
@@ -725,10 +763,25 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
          * mostly vertical drag
          */
         dragMode = DragMode.Resize;
+
+        /*
+         * but could also be a matrix drag
+         */
+        if ((evt.isAltDown() || evt.isAltGraphDown()) && (av.getAlignment()
+                .getAlignmentAnnotation()[graphStretch].graph == AlignmentAnnotation.CUSTOMRENDERER))
+        {
+          /*
+           * dragging in a matrix
+           */
+          dragMode = DragMode.MatrixSelect;
+          firstDragX = mouseDragLastX;
+          firstDragY = mouseDragLastY;
+        }
       }
     }
 
     if (dragMode == DragMode.Undefined)
+
     {
       /*
        * drag is diagonal - defer deciding whether to
@@ -755,6 +808,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
           ap.paintAlignment(false, false);
         }
       }
+      else if (dragMode == DragMode.MatrixSelect)
+      {
+        /*
+         * TODO draw a rubber band for range
+         */
+      }
       else
       {
         /*
@@ -770,6 +829,70 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     }
   }
 
+  public void matrixSelectRange(MouseEvent evt)
+  {
+    /*
+     * get geometry of drag
+     */
+    int fromY = Math.min(firstDragY, evt.getY());
+    int deltaY = Math.abs(firstDragY - evt.getY());
+    int toY = Math.max(firstDragY, evt.getY());
+
+    int[] rowIndex = getRowIndexAndOffset(fromY,
+            av.getAlignment().getAlignmentAnnotation());
+
+    // rectangular selection on matrix style annotation
+    AlignmentAnnotation cma = av.getAlignment()
+            .getAlignmentAnnotation()[rowIndex[0]];
+
+    int fromXp = Math.min(firstDragX, evt.getX());
+    int toXp = Math.max(firstDragX, evt.getX());
+    int lastX = getColumnForXPos(fromXp);
+    int currentX = getColumnForXPos(toXp);
+    ContactListI forLastX = av.getContactList(cma, lastX);
+    ContactListI forCurrentX = av.getContactList(cma, currentX);
+    if (forLastX != null && forCurrentX != null)
+    {
+      ContactGeometry lastXcgeom = new ContactGeometry(forLastX,
+              cma.graphHeight);
+      ContactGeometry.contactInterval lastXci = lastXcgeom.mapFor(
+              rowIndex[1],
+              rowIndex[1] + ((fromY == firstDragY) ? -deltaY : deltaY));
+      ContactGeometry cXcgeom = new ContactGeometry(forCurrentX,
+              cma.graphHeight);
+      ContactGeometry.contactInterval cXci = cXcgeom.mapFor(rowIndex[1],
+              rowIndex[1] + deltaY);
+      // mark rectangular region formed by drag
+      System.err.println("Matrix Selection from last(" + lastXci.cStart
+              + "," + lastXci.cEnd + ") to cur(" + cXci.cStart + ","
+              + cXci.cEnd + ")");
+      int fr, to;
+      fr = Math.min(lastXci.cStart, lastXci.cEnd);
+      to = Math.max(lastXci.cStart, lastXci.cEnd);
+      System.err.println("Marking " + fr + " to " + to);
+      for (int c = fr; c <= to; c++)
+      {
+        av.getColumnSelection().addElement(c);
+      }
+      fr = Math.min(cXci.cStart, cXci.cEnd);
+      to = Math.max(cXci.cStart, cXci.cEnd);
+      System.err.println("Marking " + fr + " to " + to);
+      for (int c = fr; c <= to; c++)
+      {
+        av.getColumnSelection().addElement(c);
+      }
+      fr = Math.min(lastX, currentX);
+      to = Math.max(lastX, currentX);
+
+      System.err.println("Marking " + fr + " to " + to);
+      for (int c = fr; c <= to; c++)
+      {
+        av.getColumnSelection().addElement(c);
+      }
+    }
+
+  }
+
   /**
    * Constructs the tooltip, and constructs and displays a status message, for
    * the current mouse position
@@ -790,21 +913,14 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    int column = (evt.getX() / av.getCharWidth())
-            + av.getRanges().getStartRes();
-    column = Math.min(column, av.getRanges().getEndRes());
-
-    if (av.hasHiddenColumns())
-    {
-      column = av.getAlignment().getHiddenColumns()
-              .visibleToAbsoluteColumn(column);
-    }
+    int column = getColumnForXPos(evt.getX());
 
     AlignmentAnnotation ann = aa[row];
     if (row > -1 && ann.annotations != null
             && column < ann.annotations.length)
     {
-      String toolTip = buildToolTip(ann, column, aa, rowAndOffset[1], av);
+      String toolTip = buildToolTip(ann, column, aa, rowAndOffset[1], av,
+              ap);
       setToolTipText(toolTip == null ? null
               : JvSwingUtils.wrapTooltip(true, toolTip));
       String msg = getStatusMessage(av.getAlignment(), column, ann,
@@ -818,6 +934,19 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
     }
   }
 
+  private int getColumnForXPos(int x)
+  {
+    int column = (x / av.getCharWidth()) + av.getRanges().getStartRes();
+    column = Math.min(column, av.getRanges().getEndRes());
+
+    if (av.hasHiddenColumns())
+    {
+      column = av.getAlignment().getHiddenColumns()
+              .visibleToAbsoluteColumn(column);
+    }
+    return column;
+  }
+
   /**
    * Answers the index in the annotations array of the visible annotation at the
    * given y position. This is done by adding the heights of visible annotations
@@ -861,7 +990,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       {
         row = i;
         res[0] = row;
-        res[1] = yPos - lheight;
+        res[1] = height - yPos;
         break;
       }
     }
@@ -879,7 +1008,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
    * @param rowAndOffset
    */
   static String buildToolTip(AlignmentAnnotation ann, int column,
-          AlignmentAnnotation[] anns, int rowAndOffset, AlignViewportI av)
+          AlignmentAnnotation[] anns, int rowAndOffset, AlignViewportI av,
+          AlignmentPanel ap)
   {
     String tooltip = null;
     if (ann.graphGroup > -1)
@@ -921,6 +1051,9 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         ContactGeometry.contactInterval ci = cgeom.mapFor(rowAndOffset,
                 rowAndOffset);
         tooltip += "Contact from " + ci.cStart + " to " + ci.cEnd;
+
+        // ap.getStructureSelectionManager().mouseOverSequence(ann.sequenceRef,
+        // new int[] {column, ci.cStart,ci.cEnd}, -1, null)
       }
     }
     return tooltip;
index 6918811..20ec5e4 100644 (file)
@@ -1184,7 +1184,7 @@ public class SeqPanel extends JPanel
     AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
 
     String tooltip = AnnotationPanel.buildToolTip(anns[rowIndex], column,
-            anns, 0, av);
+            anns, 0, av, ap);
     if (tooltip == null ? tooltip != lastTooltip
             : !tooltip.equals(lastTooltip))
     {