@@ -847,14 +847,81 @@ def trigger(self, sender, event, data=None):
847847
848848
849849class HelpGTK3 (backend_tools .ToolHelpBase ):
850- def trigger (self , * args ):
850+ def _normalize_shortcut (self , key ):
851+ """
852+ Convert Matplotlib key presses to GTK+ accelerator identifiers.
853+
854+ Related to `FigureCanvasGTK3._get_key`.
855+ """
856+ special = {
857+ 'backspace' : 'BackSpace' ,
858+ 'pagedown' : 'Page_Down' ,
859+ 'pageup' : 'Page_Up' ,
860+ 'scroll_lock' : 'Scroll_Lock' ,
861+ }
862+
863+ parts = key .split ('+' )
864+ mods = ['<' + mod + '>' for mod in parts [:- 1 ]]
865+ key = parts [- 1 ]
866+
867+ if key in special :
868+ key = special [key ]
869+ elif len (key ) > 1 :
870+ key = key .capitalize ()
871+ elif key .isupper ():
872+ mods += ['<shift>' ]
873+
874+ return '' .join (mods ) + key
875+
876+ def _show_shortcuts_window (self ):
877+ section = Gtk .ShortcutsSection ()
878+
879+ for name , tool in sorted (self .toolmanager .tools .items ()):
880+ if not tool .description :
881+ continue
882+
883+ # Putting everything in a separate group allows GTK to
884+ # automatically split them into separate columns/pages, which is
885+ # useful because we have lots of shortcuts, some with many keys
886+ # that are very wide.
887+ group = Gtk .ShortcutsGroup ()
888+ section .add (group )
889+ # A hack to remove the title since we have no group naming.
890+ group .forall (lambda widget , data : widget .set_visible (False ), None )
891+
892+ shortcut = Gtk .ShortcutsShortcut (
893+ accelerator = ' ' .join (
894+ self ._normalize_shortcut (key )
895+ for key in self .toolmanager .get_tool_keymap (name )
896+ # Will never be sent:
897+ if 'cmd+' not in key ),
898+ title = tool .name ,
899+ subtitle = tool .description )
900+ group .add (shortcut )
901+
902+ window = Gtk .ShortcutsWindow (
903+ title = 'Help' ,
904+ modal = True ,
905+ transient_for = self ._figure .canvas .get_toplevel ())
906+ section .show () # Must be done explicitly before add!
907+ window .add (section )
908+
909+ window .show_all ()
910+
911+ def _show_shortcuts_dialog (self ):
851912 dialog = Gtk .MessageDialog (
852913 self ._figure .canvas .get_toplevel (),
853914 0 , Gtk .MessageType .INFO , Gtk .ButtonsType .OK , self ._get_help_text (),
854915 title = "Help" )
855916 dialog .run ()
856917 dialog .destroy ()
857918
919+ def trigger (self , * args ):
920+ if Gtk .check_version (3 , 20 , 0 ) is None :
921+ self ._show_shortcuts_window ()
922+ else :
923+ self ._show_shortcuts_dialog ()
924+
858925
859926# Define the file to use as the GTk icon
860927if sys .platform == 'win32' :
0 commit comments