UI - Keyboard Input Code Question- Arrow Key Input? Tkinter, Gtk+?

Tags: #<Tag:0x00007fbc851163b0> #<Tag:0x00007fbc85116270>

Typical behavior with the arrow keys and collapsible lists are Left / Right Arrow will open/close the list.

Closed (Left Arrow)

Open (Right Arrow)

Up / Down Arrow moves the selection bar accordingly …

Down one Line (Down Arrow)

All good so far.

Following those actions, if the selection line is in a collapsible list section as shown above, pressing the Left Arrow should return the selection line to the next higher level of the collapsible list.

Using Finder as an example:

If I press Left Arrow with the selection line over folder.JPG


… the selection line will jump up to the next higher level.
…pressing it again will close / collapse that group.

Picard does not move the selection line on that Left Arrow input.

In this example I’m looking at the code for album.py, but the same behavior should be throughout the entire application. Does this need to be changed at each level or are there universal UI/keyboard input settings higher up in the source tree?

…and what am I looking for call wise, for intercepting keyboard input?

Like if I also want to add functionality so that Command-Q (CTRL-Q) or ESC can be used at the Quit Picard Dialog?

The keyboard can be used to fully exit from Picard, or ESC if you didn’t mean to enter Command-Q.

I Presume the code for the Quit is def show_quit_confirmation(self): in mainwindow.py

def show_quit_confirmation(self):
    unsaved_files = sum(a.get_num_unsaved_files() for a in self.tagger.albums.values())
    QMessageBox = QtWidgets.QMessageBox

    if unsaved_files > 0:
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Question)
        msg.setWindowModality(QtCore.Qt.WindowModal)
        msg.setWindowTitle(_("Unsaved Changes"))
        msg.setText(_("Are you sure you want to quit Picard?"))
        txt = ngettext(
            "There is %d unsaved file. Closing Picard will lose all unsaved changes.",
            "There are %d unsaved files. Closing Picard will lose all unsaved changes.",
            unsaved_files) % unsaved_files
        msg.setInformativeText(txt)
        cancel = msg.addButton(QMessageBox.Cancel)
        msg.setDefaultButton(cancel)
        msg.addButton(_("&Quit Picard"), QMessageBox.YesRole)
        ret = msg.exec_()

        if ret == QMessageBox.Cancel:
            return False

    return True

There (or course) are several ways to process keyboard inputs and do GUI calls… I’m not figuring out which way exactly Picard is doing UI within Python, to follow documentation against.

The way you describe it is actually how it works on Linux and Windows, but I can confirm that this does not work on macOS. I don’t know why the Qt developers decided that macOS should behave differently here. If this is a common UI pattern on macOS as well we could implement it.

To react to different key presses the corresponding widget class needs to override QtWidget.keyPressEvent. For the two itemview columns this could be done in the BaseTreeView in itemviews.py. For the file browser sidebar this is in filebrowser.py.

For manipulating the tree view the documentation in https://doc.qt.io/qt-5/qtreewidget.html is relevant.

ESC already works on all platforms, this is default functionality for Qt dialogs. Command-Q would be special, but I don’t see this being supported on other tools on macOS. Is this common? I kind of find it difficult that hitting Command-Q twice will close immediately. If one wants to implement custom behavior here the QMessageBox needs to be subclassed.

The Qt way :wink:

1 Like

Yes, it is. So it’s the Qt People… That’s it, Pass the buck. It’s been that way on Macintosh since the Exposure triangle / collapsible list was first introduced to the UI.

…furthering that, the horizontal scrolling of the window contents is something that is usually -not- defaulted to the arrow keys. With the left/right arrow, at least Picard is parsing that first, if the selection is on an expandable list line. It will do the list action first, then additional inputs will side scroll the window. That’s kind of a hybrid way to do it, but usually when you’re dealing with lists, the arrows don’t do any window scrolling.

As for the Command-Q, sure. There’s plenty of things I can quit without using the mouse. That’s what the confirmation when there are unsaved documents open is for- to make sure you actually wanted to do that. But if there’s no unchanged windows open, then most will just quit - no questions asked. As in not even display that dialog. There are some that will still confirm, which is what I presumed that Picard was doing, instead of just quitting without asking.

If there are new or changed documents open then you have to intentionally issue the quit command again, or cancel, save, and quit… and some will even combine a “Save Then Quit” option on there as well.

It’s pretty out of the ordinary to have to reach for the mouse to quit from applications.

Some, like e.g. Picard :wink:

So your proposal is if the quit confirmation dialog is shown the user can press Command-Q again and then it will really quit. And you say this is common behavior. My issue with this is that I can’t find a single app that behaves that way. Granted I’m no big macOS user, but the ones I tried (TextEdit, iTerm, Atom) don’t allow you to quit from the confirmation dialog using Command-Q. I don’t know if there is any other shortcut here. Google Chrome has some special behavior, it doesn’t show a dialog but a short message that tells the user to hold Command-Q, and holding Command-Q for a short time then really quits.

1 Like

Yes, you’re right. For some reason I had it on my mind that Picard was not doing this, and that ESC was not working from the quit dialog either. It absolutely was not previously for me though that might have been related to whatever I had going on previously by not using Python3 or something where I got different UI results running from source vs. running from a package.

Anyhow, what I’m trying to get down to is to be able to quit anyway without having to use the mouse, if I want to bail on those unsaved / changed items.

Typically an application with multiple document window support will tell you there are document(s) to be saved, would you like to review them, save and quit … or cancel.

The ones that only support a single session will ask to quit, save or cancel, and then there’s typically a way to quit anyway. That’s what I’ve got stuck in my mind with the quit dialog.

So there is no settled on definitive way to “quit anyway”, but some things allow to override the unsaved document(s) at the quit dialog. Others, yes, you’ll have to cancel, and close / delete each new / changed document before quitting. In Picard that would mean deleting or saving each item on the right that has unsaved changes.

So yes, I see where my “proposal” is ambiguous against the typical UI methods for the quitting. What I’m simply trying to do there is provide an option to quit anyway, just the same way that ESC will cancel the quit dialog. So I don’t have to reach for the mouse.

As for the arrow key behavior, that is typical UI behavior that could be applied to Picard as evidenced by the other two major platforms working that way. :slight_smile:

So for the Quit, I basically want to check for ESC -or- Q, Command-Q, whatever, so that I can actually just quit from Picard regardless.

I found some similar threads on this subject on other Python based projects. Why the Left Arrow does not jump up to the next parent level, when it’s on a sub level list.

Initial feedback there from other readers agrees that there is different behavior between macOS and Linux/Windows builds too.

I started a thread at qt.io on this as well.