Repository: mne-tools/mne-python

Issue:
Some keyboard shortcuts are broken in raw.plot
On macOS, toggling the scale bar (`s`) in an open `raw.plot` window doesn't work immediately. The scale bar is only toggled after e.g. switching to zen mode back and forth.

The help window shows incorrect shortcuts to increase/decrease window length and visible channels. For example, the window lists ⌘ + → as a shortcut to show a longer window, but the correct shortcut is fn + →. The same is true for the other three shortcuts.

F11 doesn't enter fullscreen mode, probably because this key is mapped to showing the desktop by default. I don't think we need a fullscreen shortcut on macOS because users can click the green button, but if we want to keep a shortcut we should change it to something else (at least on macOS where ^⌘F seems to be the default for full screen).

@drammock another one for you? If you don't have time I can also take a look (but not immediately).


Discussion:
I'll fix it but I'll probably need your help testing the solution
testing in a mac VM with the `macosx` backend, what I see is that pressing `s` will not immediately make a scalebar *disappear* if it's visible (but it will disappear as soon as some other event causes a redraw, such as window resize or zen mode toggle), but pressing `s` when the scalebars are hidden *will* work immediately.  Testing in the same VM with `qt5agg` backend, the `s` key works immediately as a toggle to both show and hide.  Is this consistent with what you're seeing @cbrnr ?

I also noticed that with the `macosx` backend that zen mode toggling shows/hides the scrollbars correctly, but doesn't actually resize the main axes to use the freed space when the scalebars are hidden.  This is true even if you trigger a draw event by resizing the window.

Resolving patch:
diff --git a/mne/viz/_figure.py b/mne/viz/_figure.py
--- a/mne/viz/_figure.py
+++ b/mne/viz/_figure.py
@@ -979,8 +979,8 @@ def _get_help_text(self):
         has_proj = bool(len(self.mne.projs))
         # adapt keys to different platforms
         is_mac = platform.system() == 'Darwin'
-        dur_keys = ('⌘ + ←', '⌘ + →') if is_mac else ('Home', 'End')
-        ch_keys = ('⌘ + ↑', '⌘ + ↓') if is_mac else ('Page up', 'Page down')
+        dur_keys = ('fn + ←', 'fn + →') if is_mac else ('Home', 'End')
+        ch_keys = ('fn + ↑', 'fn + ↓') if is_mac else ('Page up', 'Page down')
         # adapt descriptions to different instance types
         ch_cmp = 'component' if is_ica else 'channel'
         ch_epo = 'epoch' if is_epo else 'channel'
@@ -1026,7 +1026,7 @@ def _get_help_text(self):
             ('p', 'Toggle draggable annotations' if is_raw else None),
             ('s', 'Toggle scalebars' if not is_ica else None),
             ('z', 'Toggle scrollbars'),
-            ('F11', 'Toggle fullscreen'),
+            ('F11', 'Toggle fullscreen' if not is_mac else None),
             ('?', 'Open this help window'),
             ('esc', 'Close focused figure or dialog window'),
             ('_MOUSE INTERACTION', ' '),
@@ -1692,8 +1692,17 @@ def _toggle_bad_epoch(self, event):
     # SCROLLBARS
     # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
 
+    def _update_zen_mode_offsets(self):
+        """Compute difference between main axes edges and scrollbar edges."""
+        self.mne.fig_size_px = self._get_size_px()
+        self.mne.zen_w = (self.mne.ax_vscroll.get_position().xmax -
+                          self.mne.ax_main.get_position().xmax)
+        self.mne.zen_h = (self.mne.ax_main.get_position().ymin -
+                          self.mne.ax_hscroll.get_position().ymin)
+
     def _toggle_scrollbars(self):
         """Show or hide scrollbars (A.K.A. zen mode)."""
+        self._update_zen_mode_offsets()
         # grow/shrink main axes to take up space from (or make room for)
         # scrollbars. We can't use ax.set_position() because axes are
         # locatable, so we use subplots_adjust
@@ -1703,7 +1712,6 @@ def _toggle_scrollbars(self):
         # if should_show, bottom margin moves up; right margin moves left
         margins['bottom'] += (1 if should_show else -1) * self.mne.zen_h
         margins['right'] += (-1 if should_show else 1) * self.mne.zen_w
-        # squeeze a bit more because we don't need space for xlabel now
         self.subplots_adjust(**margins)
         # handle x-axis label
         self.mne.zen_xlabel.set_visible(not should_show)
@@ -1793,7 +1801,7 @@ def _toggle_scalebars(self, event):
             self._show_scalebars()
         # toggle
         self.mne.scalebars_visible = not self.mne.scalebars_visible
-        self.canvas.draw_idle()
+        self._redraw(update_data=False)
 
     def _draw_one_scalebar(self, x, y, ch_type):
         """Draw a scalebar."""
@@ -2255,11 +2263,7 @@ def _browse_figure(inst, **kwargs):
                   figsize=figsize, **kwargs)
     # initialize zen mode (can't do in __init__ due to get_position() calls)
     fig.canvas.draw()
-    fig.mne.fig_size_px = fig._get_size_px()
-    fig.mne.zen_w = (fig.mne.ax_vscroll.get_position().xmax -
-                     fig.mne.ax_main.get_position().xmax)
-    fig.mne.zen_h = (fig.mne.ax_main.get_position().ymin -
-                     fig.mne.ax_hscroll.get_position().ymin)
+    fig._update_zen_mode_offsets()
     # if scrollbars are supposed to start hidden, set to True and then toggle
     if not fig.mne.scrollbars_visible:
         fig.mne.scrollbars_visible = True


Test patch: