JAL-3638 shift+arrow keys in cursor mode jumps cursor in a gapped region to next...
authorJim Procter <jprocter@issues.jalview.org>
Tue, 2 Jun 2020 17:03:32 +0000 (18:03 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Sat, 4 Jul 2020 13:22:10 +0000 (14:22 +0100)
help/help/html/keys.html
src/jalview/gui/AlignFrame.java
src/jalview/gui/SeqPanel.java

index 1a5fc18..f96391f 100755 (executable)
       <td><strong>Cursor Keys<br> (Arrow Keys)
       </strong></td>
       <td>Cursor</td>
-      <td>Move cursor around alignment</td>
+      <td>Move cursor around alignment.<br /> Press SHIFT to move
+        cursor from an aligned region to next gap, or to the next
+        aligned region when at a gap.
+      </td>
     </tr>
     <tr>
       <td><strong>Page Up</strong></td>
index 2db0884..0a42036 100644 (file)
@@ -536,7 +536,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().moveCursor(0, 1);
+            alignPanel.getSeqPanel().moveCursor(0, 1, evt.isShiftDown());
           }
           break;
 
@@ -547,7 +547,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().moveCursor(0, -1);
+            alignPanel.getSeqPanel().moveCursor(0, -1,evt.isShiftDown());
           }
 
           break;
@@ -560,7 +560,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().moveCursor(-1, 0);
+            alignPanel.getSeqPanel().moveCursor(-1, 0, evt.isShiftDown());
           }
 
           break;
@@ -572,7 +572,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().moveCursor(1, 0);
+            alignPanel.getSeqPanel().moveCursor(1, 0, evt.isShiftDown());
           }
           break;
 
index def4be1..407acd6 100644 (file)
@@ -460,47 +460,80 @@ public class SeqPanel extends JPanel
 
   void moveCursor(int dx, int dy)
   {
-    seqCanvas.cursorX += dx;
-    seqCanvas.cursorY += dy;
-
+    moveCursor(dx, dy,false);
+  }
+  void moveCursor(int dx, int dy, boolean nextWord)
+  {
     HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 
-    if (av.hasHiddenColumns() && !hidden.isVisible(seqCanvas.cursorX))
+    if (nextWord)
     {
-      int original = seqCanvas.cursorX - dx;
       int maxWidth = av.getAlignment().getWidth();
-
-      if (!hidden.isVisible(seqCanvas.cursorX))
-      {
-        int visx = hidden.absoluteToVisibleColumn(seqCanvas.cursorX - dx);
-        int[] region = hidden.getRegionWithEdgeAtRes(visx);
-
-        if (region != null) // just in case
+      int maxHeight=av.getAlignment().getHeight();
+      SequenceI seqAtRow = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
+      // look for next gap or residue
+      boolean isGap = Comparison.isGap(seqAtRow.getCharAt(seqCanvas.cursorX));
+      int p = seqCanvas.cursorX,lastP,r=seqCanvas.cursorY,lastR;
+      do
+      {
+        lastP = p;
+        lastR = r;
+        if (dy != 0)
         {
-          if (dx == 1)
+          r += dy;
+          if (r < 0)
           {
-            // moving right
-            seqCanvas.cursorX = region[1] + 1;
+            r = 0;
           }
-          else if (dx == -1)
+          if (r >= maxHeight)
           {
-            // moving left
-            seqCanvas.cursorX = region[0] - 1;
+            r = maxHeight - 1;
           }
+          seqAtRow = av.getAlignment().getSequenceAt(r);
         }
-        seqCanvas.cursorX = (seqCanvas.cursorX < 0) ? 0 : seqCanvas.cursorX;
-      }
+        p = nextVisible(hidden, maxWidth, p, dx);
+      } while ((dx != 0 ? p != lastP : r != lastR)
+              && isGap == Comparison.isGap(seqAtRow.getCharAt(p)));
+      seqCanvas.cursorX=p;
+      seqCanvas.cursorY=r;
+    } else {
+      int maxWidth = av.getAlignment().getWidth();
+      seqCanvas.cursorX = nextVisible(hidden, maxWidth, seqCanvas.cursorX, dx);
+      seqCanvas.cursorY += dy;
+    }
+    scrollToVisible(false);
+  }
 
-      if (seqCanvas.cursorX >= maxWidth
-              || !hidden.isVisible(seqCanvas.cursorX))
+  private int nextVisible(HiddenColumns hidden,int maxWidth, int original, int dx)
+  {
+    int newCursorX=original+dx;
+    if (av.hasHiddenColumns() && !hidden.isVisible(newCursorX))
+    {
+      int visx = hidden.absoluteToVisibleColumn(newCursorX - dx);
+      int[] region = hidden.getRegionWithEdgeAtRes(visx);
+
+      if (region != null) // just in case
       {
-        seqCanvas.cursorX = original;
+        if (dx == 1)
+        {
+          // moving right
+          newCursorX = region[1] + 1;
+        }
+        else if (dx == -1)
+        {
+          // moving left
+          newCursorX = region[0] - 1;
+        }
       }
     }
-
-    scrollToVisible(false);
+    newCursorX = (newCursorX < 0) ? 0 : newCursorX;
+    if (newCursorX >= maxWidth
+            || !hidden.isVisible(newCursorX))
+    {
+      newCursorX = original;
+    }
+    return newCursorX;
   }
-
   /**
    * Scroll to make the cursor visible in the viewport.
    *