JAL-3364 align split frame sequence panels with wrapped view scale left
[jalview.git] / src / jalview / gui / SplitFrame.java
index d28bb14..fd0ec63 100644 (file)
@@ -29,7 +29,6 @@ import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.Component;
-import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyAdapter;
@@ -43,6 +42,8 @@ import java.util.Map.Entry;
 import javax.swing.AbstractAction;
 import javax.swing.InputMap;
 import javax.swing.JComponent;
+import javax.swing.JDesktopPane;
+import javax.swing.JInternalFrame;
 import javax.swing.JMenuItem;
 import javax.swing.KeyStroke;
 import javax.swing.event.InternalFrameAdapter;
@@ -85,8 +86,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
    */
   protected void init()
   {
-    getTopFrame().setSplitFrame(this);
-    getBottomFrame().setSplitFrame(this);
+    getTopFrame().setSplitFrame(this, true);
+    getBottomFrame().setSplitFrame(this, false);
     getTopFrame().setVisible(true);
     getBottomFrame().setVisible(true);
 
@@ -160,26 +161,32 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
    */
   public void adjustLayout()
   {
+    final AlignViewport topViewport = ((AlignFrame) getTopFrame()).viewport;
+    final AlignViewport bottomViewport = ((AlignFrame) getBottomFrame()).viewport;
+
     /*
-     * Ensure sequence ids are the same width so sequences line up
+     * Ensure sequence ids are the same width so sequences line up;
+     * reduce the idwidth of a panel with a longer wrapped left scale
      */
-    int w1 = ((AlignFrame) getTopFrame()).getViewport().getIdWidth();
-    int w2 = ((AlignFrame) getBottomFrame()).getViewport().getIdWidth();
+    int w1 = topViewport.getIdWidth();
+    int w2 = bottomViewport.getIdWidth();
+    int topScaleLeft = topViewport.getWrapAlignment()
+            ? ((AlignFrame) getTopFrame()).alignPanel
+                    .getSeqPanel().seqCanvas.getLabelWidthWest()
+            : 0;
+    int bottomScaleLeft = bottomViewport.getWrapAlignment()
+            ? ((AlignFrame) getBottomFrame()).alignPanel
+                    .getSeqPanel().seqCanvas.getLabelWidthWest()
+            : 0;
     int w3 = Math.max(w1, w2);
-    if (w1 != w3)
-    {
-      ((AlignFrame) getTopFrame()).getViewport().setIdWidth(w3);
-    }
-    if (w2 != w3)
-    {
-      ((AlignFrame) getBottomFrame()).getViewport().setIdWidth(w3);
-    }
+    topViewport
+            .setIdWidth(w3 - Math.max(0, topScaleLeft - bottomScaleLeft));
+    bottomViewport
+            .setIdWidth(w3 - Math.max(0, bottomScaleLeft - topScaleLeft));
 
     /*
      * Scale protein to either 1 or 3 times character width of dna
      */
-    final AlignViewport topViewport = ((AlignFrame) getTopFrame()).viewport;
-    final AlignViewport bottomViewport = ((AlignFrame) getBottomFrame()).viewport;
     final AlignmentI topAlignment = topViewport.getAlignment();
     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
     AlignmentViewport cdna = topAlignment.isNucleotide() ? topViewport
@@ -191,15 +198,21 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
       int scale = protein.isScaleProteinAsCdna() ? 3 : 1;
       protein.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
     }
+
+    repaint();
   }
 
   /**
-   * Adjust the divider for a sensible split of the real estate (for example,
+   * Adjusts the divider for a sensible split of the real estate (for example,
    * when many transcripts are shown with a single protein). This should only be
    * called after the split pane has been laid out (made visible) so it has a
-   * height.
+   * height. The aim is to avoid unnecessary vertical scroll bars, while
+   * ensuring that at least 2 sequences are visible in each panel.
+   * <p>
+   * Once laid out, the user may choose to customise as they wish, so this
+   * method is not called again after the initial layout.
    */
-  protected void adjustDivider()
+  protected void adjustInitialLayout()
   {
     AlignFrame topFrame = (AlignFrame) getTopFrame();
     AlignFrame bottomFrame = (AlignFrame) getBottomFrame();
@@ -224,31 +237,27 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     int bottomCharHeight = bottomViewport.getViewStyle().getCharHeight();
 
     /*
-     * calculate the minimum ratio that leaves at least 
-     * two sequences visible in the top panel
+     * calculate the minimum ratio that leaves at least the height 
+     * of two sequences (after rounding) visible in the top panel
      */
     int topPanelHeight = topFrame.getHeight();
+    int bottomPanelHeight = bottomFrame.getHeight();
     int topSequencesHeight = topFrame.alignPanel.getSeqPanel().seqCanvas
             .getHeight();
     int topPanelMinHeight = topPanelHeight
-            - Math.max(0,
-                    topSequencesHeight - 2 * topViewport.getCharHeight());
-    int myHeight = getHeight();
-    double minRatio = topPanelMinHeight / (double) myHeight;
+            - Math.max(0, topSequencesHeight - 3 * topCharHeight);
+    double totalHeight = (double) topPanelHeight + bottomPanelHeight;
+    double minRatio = topPanelMinHeight / totalHeight;
 
     /*
-     * calculate the maximum ratio that leaves at least 
-     * two sequences visible in the bottom panel
+     * calculate the maximum ratio that leaves at least the height 
+     * of two sequences (after rounding) visible in the bottom panel
      */
-    int bottomPanelHeight = bottomFrame.getHeight();
     int bottomSequencesHeight = bottomFrame.alignPanel.getSeqPanel().seqCanvas
             .getHeight();
     int bottomPanelMinHeight = bottomPanelHeight
-            - Math.max(
-                    0,
-                    bottomSequencesHeight - 2
-                            * bottomViewport.getCharHeight());
-    double maxRatio = (myHeight - bottomPanelMinHeight) / (double) myHeight;
+            - Math.max(0, bottomSequencesHeight - 3 * bottomCharHeight);
+    double maxRatio = (totalHeight - bottomPanelMinHeight) / totalHeight;
 
     /*
      * estimate ratio of (topFrameContent / bottomFrameContent)
@@ -268,7 +277,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
      */
     ratio = Math.min(ratio, maxRatio);
     ratio = Math.max(ratio, minRatio);
-    // setRelativeDividerLocation(ratio);
+    setRelativeDividerLocation(ratio);
   }
 
   /**
@@ -412,7 +421,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
      * Ctrl-W / Cmd-W - close view or window
      */
     KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W,
-            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+            jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
     action = new AbstractAction()
     {
       @Override
@@ -433,7 +442,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
      * Ctrl-T / Cmd-T open new view
      */
     KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T,
-            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+            jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
     AbstractAction action = new AbstractAction()
     {
       @Override
@@ -539,7 +548,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
       topFrame.setDisplayedView(newTopPanel);
     }
 
-    newBottomPanel.av.viewName = newTopPanel.av.viewName;
+    newBottomPanel.av.setViewName(newTopPanel.av.getViewName());
     newTopPanel.av.setCodingComplement(newBottomPanel.av);
 
     /*
@@ -773,7 +782,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
      * Ctrl-F / Cmd-F open Finder dialog, 'focused' on the right alignment
      */
     KeyStroke key_cmdF = KeyStroke.getKeyStroke(KeyEvent.VK_F,
-            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
+            jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx(), false);
     AbstractAction action = new AbstractAction()
     {
       @Override
@@ -789,4 +798,29 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     };
     overrideKeyBinding(key_cmdF, action);
   }
+
+  /**
+   * Override to do nothing if triggered from one of the child frames
+   */
+  @Override
+  public void setSelected(boolean selected) throws PropertyVetoException
+  {
+    JDesktopPane desktopPane = getDesktopPane();
+    JInternalFrame fr = desktopPane == null ? null
+            : desktopPane.getSelectedFrame();
+    if (fr == getTopFrame() || fr == getBottomFrame())
+    {
+      /* 
+       * patch for JAL-3288 (deselecting top/bottom frame closes popup menu); 
+       * it may be possible to remove this method in future
+       * if the underlying Java behaviour changes
+       */
+      if (selected)
+      {
+        moveToFront();
+      }
+      return;
+    }
+    super.setSelected(selected);
+  }
 }