Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the star ratings in the tracks view editable via keyboard #13717

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

cr7pt0gr4ph7
Copy link
Contributor

@cr7pt0gr4ph7 cr7pt0gr4ph7 commented Oct 2, 2024

It is now possible to press enter the edit key (F2, or, once #13148 is merged, 'R` resp. the confiugured edit key) on a selected "star rating" to then change the rating via the keyboard (either left/right arrow keys or numbers). Changing the rating using the mouse is still possible, and should work & interact with the keyboard edits as expected.

ezgif-6-299426cc3f

But why is this PR so large?

The code for handling the actual keyboard edits is quite simple. Nearly all of the complexity relates to handling the interaction between editing via mouse hover, editing via keyboard and the assumptions of the Qt QTableView framework code.

In short: Cells in the QTableView can either be in "edit mode" or "display mode". Pressing the edit key should enter edit mode, canceling or committing the edit should leave edit mode. BUT: The cells should also automatically enter edit mode when the mouse hovers over the cell, and exit it when the mouse leaves the cell. The rating should also temporarily adapt to the position of the mouse when hovering over the cell. But what happens e.g. when the user presses the edit key while already hovering over the cell?

All in all, the desired (and hereby implemented) behavior boils down to the following state machine:

image
PlantUML Diagram

All commits have been extensively documented. If I may, I would recommend reviewing the commits in isolation.

…itor with QAbstractItemDelegatePrivate::_q_commitDataAndCloseEditor

...by more closely adhering to the interface contract of
the closeEditor() signal. See also the Qt code here:

https://github.com/qt/qtbase/blob/faae3dc6b15e3d8754b15a7cfb22b6a797fd2e36/src/widgets/itemviews/qabstractitemdelegate.cpp#L587
The keyboard controls are only active when the eventFilter
is installed, which is only the case for non-persistent editors.
Persistent editors (i.e. those opened using openPersistentEditor)
do not receive keyboard events via their eventFilter.
@cr7pt0gr4ph7 cr7pt0gr4ph7 force-pushed the ready-for-merge/fix-star-rating-editor branch 3 times, most recently from c162ca7 to c7e0415 Compare October 2, 2024 15:11
…r control

...and close the persistent editor in those cases.

This is important for keeping the our internal bookkeeping
in sync with the Qt framework state - the former is required
to work around some quirks related to the two ways of
interacting with the StarEditor (by mouse and by keyboard)
and how this interacts with the assumptions of QTableView.

                ====================
                = More information =
                ====================

The StarRating control can be edited via mouse, keyboard, or
both at the same time. The following transitions are currently
handled correctly (marked by ✓) resp. affected by this change
(marked by =>):

       [✓] "Not editing"       -> "Edit via mouse"          (on mouseEnter)
       [✓] "Not editing"       -> "Edit via keyboard"       (on editKeyPressed)

[ ] => [✓] "Edit via mouse"    -> "Not editing"             (on mouseLeave)
       [ ] "Edit via mouse"    -> "Edit via keyboard+mouse" (on editKeyPressed)

       [✓] "Edit via keyboard" -> "Not editing"             (on exitKeyPressed)
       [✓] "Edit via keyboard" -> "Edit via keyboard+mouse" (on mouseEnter)

       [ ] "Edit via keyboard+mouse" -> "Edit via mouse"    (on exitKeyPressed)
[ ] => [~] "Edit via keyboard+mouse" -> "Edit via keyboard" (on mouseLeave)
@cr7pt0gr4ph7 cr7pt0gr4ph7 force-pushed the ready-for-merge/fix-star-rating-editor branch from c7e0415 to 75836e7 Compare October 2, 2024 15:14
…tEditorOpen

...and extract common code into separate methods.
@cr7pt0gr4ph7 cr7pt0gr4ph7 force-pushed the ready-for-merge/fix-star-rating-editor branch from 75836e7 to a83e4e4 Compare October 2, 2024 17:52
…use edit mode" on edit key pressed

Correctly handle the case of a user pressing the edit key while the
mouse is also hovering over the focused cell.

Without this special handling, the pressing the edit key on a cell
would simply be ignored if the mouse is hovering over that cell,
which would most certainly break user expectations.

                ====================
                = More information =
                ====================

The StarRating control can be edited via mouse, keyboard, or
both at the same time. The following transitions are currently
handled correctly resp. affected by this change:

       [✓] "Not editing"       -> "Edit via mouse"          (on mouseEnter)
       [✓] "Not editing"       -> "Edit via keyboard"       (on editKeyPressed)

       [✓] "Edit via mouse"    -> "Not editing"             (on mouseLeave)
[ ] => [✓] "Edit via mouse"    -> "Edit via keyboard+mouse" (on editKeyPressed)

       [✓] "Edit via keyboard" -> "Not editing"             (on exitKeyPressed)
       [✓] "Edit via keyboard" -> "Edit via keyboard+mouse" (on mouseEnter)

       [ ] "Edit via keyboard+mouse" -> "Edit via mouse"    (on exitKeyPressed)
       [~] "Edit via keyboard+mouse" -> "Edit via keyboard" (on mouseLeave)
…mouse edit mode"

This is important for the case when all of the following is true:

* The user is currently editing a star rating cell via the keyboard.
* The mouse cursor is inside that cell.
* The user finishes editing by pressing the Return key or the Escape key.

Without the special handling in place, the user would have to move
the mouse outside the cell and then back in to see the cell react
to the movements of the mouse cursor again.

                ====================
                = More information =
                ====================

The StarRating control can be edited via mouse, keyboard, or
both at the same time. The following transitions are currently
handled correctly (marked by ✓) resp. affected by this change
(marked by =>):

       [✓] "Not editing"       -> "Edit via mouse"          (on mouseEnter)
       [✓] "Not editing"       -> "Edit via keyboard"       (on editKeyPressed)

       [✓] "Edit via mouse"    -> "Not editing"             (on mouseLeave)
       [✓] "Edit via mouse"    -> "Edit via keyboard+mouse" (on editKeyPressed)

       [✓] "Edit via keyboard" -> "Not editing"             (on exitKeyPressed)
       [✓] "Edit via keyboard" -> "Edit via keyboard+mouse" (on mouseEnter)

[ ] => [✓] "Edit via keyboard+mouse" -> "Edit via mouse"    (on exitKeyPressed)
       [~] "Edit via keyboard+mouse" -> "Edit via keyboard" (on mouseLeave)
…ctItemView

QAbstractItemView doesn't like it when we try to open an editor while
the closing of the previously open editor is not fully finished,
because that messes up its internal state.

We avoid this race condition by deferring the restore until we have
returned to the event loop (using basically the same technique as
QObject::deleteLater().
Contrary to its name, the QAbstractItemView::closePersistentEditor()
method will also close a non-persistent editor which is present at
the specified QModelIndex.

If we do not detect this case, moving the mouse outside of a star
rating editor that is currently in "keyboard edit mode" would both
involuntarily exit the edit mode and break our internal state.

                ====================
                = More information =
                ====================

The StarRating control can be edited via mouse, keyboard, or
both at the same time. The following transitions are currently
handled correctly (marked by ✓) resp. affected by this change
(marked by =>):

       [✓] "Not editing"       -> "Edit via mouse"          (on mouseEnter)
       [✓] "Not editing"       -> "Edit via keyboard"       (on editKeyPressed)

       [✓] "Edit via mouse"    -> "Not editing"             (on mouseLeave)
       [✓] "Edit via mouse"    -> "Edit via keyboard+mouse" (on editKeyPressed)

       [✓] "Edit via keyboard" -> "Not editing"             (on exitKeyPressed)
       [✓] "Edit via keyboard" -> "Edit via keyboard+mouse" (on mouseEnter)

       [✓] "Edit via keyboard+mouse" -> "Edit via mouse"    (on exitKeyPressed)
[~] => [✓] "Edit via keyboard+mouse" -> "Edit via keyboard" (on mouseLeave)
…edit mode"

This matches the behavior of the textual controls, where the border color
and background color change depending on whether you are currently editing
the text field, or are just focused on the cell.
@cr7pt0gr4ph7 cr7pt0gr4ph7 force-pushed the ready-for-merge/fix-star-rating-editor branch from a83e4e4 to c59a384 Compare October 2, 2024 19:02
@ronso0
Copy link
Member

ronso0 commented Oct 5, 2024

Just a note

It is now possible to press enter on a selected "star rating" to then change the rating via the keyboard

Enter/Return currently triggers the configured double-click action, so in order to use Enter one woud have to select 'ignore' in the preferences, right?
I assume you'll map this to the new Edit key introduced in #13148? (once that's merged)

case Qt::Key_9: {
newRating = 9;
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another quick note:
currently, star ratings range from 0-5, so let's use onyl those keys, and add a note to

static constexpr int kMaxRating = 5;

Copy link
Contributor Author

@cr7pt0gr4ph7 cr7pt0gr4ph7 Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Edit: Sorry, reply got way longer than intended. TLDR: It causes no issues and is not more complex to maintain than a TODO comment in an "unrelated" file. If you insist, I have no problem with removing those lines though).


I see your point, but I'd argue in favor of keeping it the way it currently is:

  • User Interaction: We prevent all key press events from moving up the parent chain anyway while in edit mode (see line 201) to be consistent with the way the other editors work, so the user does not gain something from not handling the keys 6 to 9.
    // Prevent other keys from being handled as global keyboard shortcuts.
    // This matches the behavior of the other edit controls.
    return true;

    We clamp to the valid rating range anyway, so I even think supporting all numbers on the numpad makes this feature ever so slightly more discoverable.
  • API Consistency: StarRating has a maxStarCount method, so I (as a developer) would in principle expect StarEditor it to work nicely with every StarRating object I pass it, including those with max ratings other than 5, if I were to reuse it in some other place.
    explicit StarRating(
    int starCount = kMinStarCount,
    int maxStarCount = mixxx::TrackRecord::kMaxRating - mixxx::TrackRecord::kMinRating);
    void paint(QPainter* painter, const QRect& rect) const;
    QSize sizeHint() const;
    int starCount() const {
    return m_starCount;
    }
    int maxStarCount() const {
    return m_maxStarCount;
    }
  • Code complexity: If not for user/developer experience: What is to be gained from replacing a few lines of simple, perfectly working code with a TODO comment in an "unrelated" file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, your points are valid.

Mine was simply about YAGNI ; )

Copy link
Contributor Author

@cr7pt0gr4ph7 cr7pt0gr4ph7 Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No offense meant or taken ; )

YAGNI is valid, but as always it's a tradeoff : )

So, ready to merge if there are no other objections?

@cr7pt0gr4ph7
Copy link
Contributor Author

Just a note

It is now possible to press enter on a selected "star rating" to then change the rating via the keyboard

Enter/Return currently triggers the configured double-click action, so in order to use Enter one woud have to select 'ignore' in the preferences, right? I assume you'll map this to the new Edit key introduced in #13148? (once that's merged)

Good catch, this was an error I made while writing the summary. Yes, it's mapped to the edit action (triggered by F2, or also custom keys in the future) like with any other editable cell. I've updated the PR description.

@cr7pt0gr4ph7 cr7pt0gr4ph7 force-pushed the ready-for-merge/fix-star-rating-editor branch from 013c47f to 05e3874 Compare October 10, 2024 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants