porcupine icon indicating copy to clipboard operation
porcupine copied to clipboard

navigating Porcupine without mouse

Open Akuli opened this issue 3 years ago • 3 comments

Porcupine has 3 main widgets where you will likely want to have your keyboard focus:

  • The editing area itself
  • The output of commands at bottom (press F4 to show/hide)
  • The directory tree (at left)

Currently it's possible to navigate between these without clicking the mouse:

  • To focus directory tree, press Alt+Shift+T.
  • To focus the file you're editing, press Ctrl+PageDown followed by Ctrl+PageUp. This toggles between two tabs, and when switching a tab, the text widget is focused automatically. If you only have one tab opened, you need to open another one for this to work.
  • To focus the output, press Alt+Shift+T followed by Shift+Tab.

Ideally there would be separate key bindings for all of these. For example:

  • To focus the directory tree, press Alt+Shift+T.
  • To focus the file you're editing, press Alt+Shift+F (F for File, could also be e.g. E for Editing).
  • To focus the output of commands, press Alt+Shift+C (C for Commands, not O because it's too far away on keyboard).

Akuli avatar May 26 '22 20:05 Akuli

Maybe the key bindings should be Alt+Shift+D, Alt+Shift+F and Alt+Shift+C. The location of D, F and C keys on the keyboard resembles the UI layout: editing area (F) is on the right side of directory tree (D), and command output (C) is below.

Akuli avatar May 26 '22 20:05 Akuli

@Akuli are all these keybindings setup in default_keybindings.tcl?

lawson89 avatar Oct 17 '22 18:10 lawson89

Currently only the directory tree has a keybinding. It's defined here:

https://github.com/Akuli/porcupine/blob/4c52560f02c6d6eaffcbd34b196c975b1a5f39f2/porcupine/default_keybindings.tcl#L86

rdbende avatar Oct 17 '22 18:10 rdbende

I'm happy to try to fix this issue but would need some guidance. I don't know TCL at all but would I add two new keybindings in default_keybinds.tcl and two new menu entries for <<View/Focus active file>> and <<View/Focus command output>> and then wire up the event handling on the python side?

lawson89 avatar Nov 07 '22 13:11 lawson89

Setting this up is really quite simple. The code examples below are currently in Porcupine and can be found with git grep "Focus directory tree".

You need to create the menu item. You don't need to specify anything else than the text (label) and a callback function (command).

    menubar.get_menu("View").add_command(
        label="Focus directory tree", command=partial(_focus_treeview, tree)
    )

(You can set command to whatever you need, here the purpose of partial is to pass the tree as an argument to it)

This causes a clickable item in the View menu to show up, but doesn't create any convenient way to invoke it with keyboard. Configuring that is just one line of Tcl in default_keybidings.tcl:

event add "<<Menubar:View/Focus directory tree>>" <$alt_ish-T>

Here $alt_ish takes the value of the variable alt_ish, which is usually Alt, but on MacOS it is Control because the Alt key has a special meaning. The uppercase T means that Shift key must be held down as well, so this actually associates Alt+Shift+T (or Control+Shift+T on MacOS) with the menu item.

The way these <<Menubar:...>> bindings work is specific to Porcupine, and it's implemented in _update_keyboard_shortcuts_inside_submenus() in menubar.py. Its purpose is to make configuring key bindings easy and concise with a simple Tcl file: you don't need to add any platform-specific if statements when creating the menu in Python, for example.

Akuli avatar Nov 08 '22 13:11 Akuli

Ok great - I'll take a shot at this over the weekend

lawson89 avatar Nov 09 '22 19:11 lawson89

@Akuli ok, so the directory tree and the command output were no problem.

But I don't see how to select the active tab again. I have a callback firing which I modeled after the tab order plugin

I thought it would just be the below - but altho I don't get an exception it doesn't do anything tab = get_tab_manager().select() # get current tab index = get_tab_manager().index(tab) #get the index get_tab_manager().select(index)

What am I missing? Thanks!

lawson89 avatar Nov 11 '22 21:11 lawson89

By "select the active tab again", I guess you mean focusing the text widget of the tab. Just do tab.textwidget.focus().

Porcupine focuses the text widget by default when switching tabs, in this line of tabs.py:

        self.bind("<<TabSelected>>", (lambda event: self.textwidget.focus()), add=True)

Akuli avatar Nov 12 '22 19:11 Akuli

ok let me know of any changes after you have had a chance to review PR I was guessing on the menu entry locations so you may want them moved

lawson89 avatar Nov 13 '22 01:11 lawson89

Fixed in #1217.

Akuli avatar Nov 13 '22 19:11 Akuli