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
fix various keybinding/shortcut bugs #5604
Conversation
Codecov Report
@@ Coverage Diff @@
## main #5604 +/- ##
==========================================
+ Coverage 88.30% 89.86% +1.55%
==========================================
Files 611 611
Lines 51621 51629 +8
==========================================
+ Hits 45584 46396 +812
+ Misses 6037 5233 -804
|
I tested this (along with the app-model PR) and it all worked as advertised! 🎉 |
if event_key in ( | ||
Qt.Key.Key_Control, | ||
Qt.Key.Key_Shift, | ||
Qt.Key.Key_Alt, | ||
Qt.Key.Key_Meta, | ||
Qt.Key.Key_Delete, | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if event_key in ( | |
Qt.Key.Key_Control, | |
Qt.Key.Key_Shift, | |
Qt.Key.Key_Alt, | |
Qt.Key.Key_Meta, | |
Qt.Key.Key_Delete, | |
): | |
if event_key in { | |
Qt.Key.Key_Control, | |
Qt.Key.Key_Shift, | |
Qt.Key.Key_Alt, | |
Qt.Key.Key_Meta, | |
Qt.Key.Key_Delete, | |
}: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the advantage of switching to a set instead of a tuple here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be speedup and style.
But I do some additional tests and it looks like in this case the speedup is not observed:
In [14]: %timeit Qt.Key.Key_Control in (Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,)
6.84 µs ± 380 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [15]: %timeit Qt.Key.Key_Delete in (Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,)
6.95 µs ± 131 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [16]: %timeit Qt.Key.Key_Control in {Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,}
6.83 µs ± 159 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [17]: %timeit Qt.Key.Key_Delete in {Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,}
7.05 µs ± 323 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
The additional test shows that creation time is essential:
In [18]: a = {Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,}
In [19]: b = (Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,)
In [20]: %timeit Qt.Key.Key_Delete in a
1.04 µs ± 29.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [21]: %timeit Qt.Key.Key_Delete in b
1.08 µs ± 22.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [22]: %timeit Qt.Key.Key_Control in b
966 ns ± 43.4 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [23]: %timeit Qt.Key.Key_Control in a
958 ns ± 18 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
So next test:
In [10]: event_key = Qt.Key.Key_Control
In [24]: %timeit event_key in a
52.8 ns ± 4.48 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [25]: %timeit event_key in b
41 ns ± 0.744 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [26]: event_key = Qt.Key.Key_Delete
In [27]: %timeit event_key in a
47.4 ns ± 0.934 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [28]: %timeit event_key in b
76.6 ns ± 0.942 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
but put this in function does not help:
In [34]: def check_set(key):
...: return key in {Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,}
...:
In [35]: def check_tuple(key):
...: return key in (Qt.Key.Key_Control, Qt.Key.Key_Shift, Qt.Key.Key_Alt, Qt.Key.Key_Meta, Qt.Key.Key_Delete,)
...:
In [36]: event_key = Qt.Key.Key_Delete
In [37]: %timeit check_set(event_key)
5.96 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [38]: %timeit check_tuple(event_key)
5.84 µs ± 219 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [39]: event_key = Qt.Key.Key_Control
In [40]: %timeit check_set(event_key)
5.85 µs ± 104 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
In [41]: %timeit check_tuple(event_key)
5.81 µs ± 136 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
So finaly checks show that access to qt enum members is slow
In [50]: %timeit Qt.Key.Key_Control == Qt.Key.Key_Control
1.86 µs ± 20.1 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [51]: %timeit hash(event_key)
54.8 ns ± 2.46 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [52]: %timeit hash(Qt.Key.Key_Control)
958 ns ± 15.8 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [53]: %timeit event_key == event_key
34.2 ns ± 0.577 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
So everything that comes from python data structures is not important in access to qt enums.
So only style left.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I can put this set in a constant then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Marking red to avoid accidental merge, since it depends on an external pr to be merged and incorporated as dependency.
Why test are passing in cases when this should not work with not fixed app-model? |
Same reason they pass without this PR at all? 🤔 |
So it means that this PR does not contain proper test? 🤔 |
For the symbol swapping I can create tests since that would be fairly trivial (with patching I think). I was also thinking of straight-up porting this logic to app-model (see this issue), and we could test there, what do you think of doing that at the cost of this PR taking a bit longer? We could then make a release on app-model for that and the other dependency for this PR since they're related and not stagger dependency bumping. The GUI aspect is a bit more difficult to test but I could try covering it. Much of the codebase lacks proper GUI tests. |
Does that also includes fixes of #5064 ? |
It does not, but I can look into porting that over too. |
it does fix #5047 however |
That's fine, I can rebase later. I would just hope that there were more review/merge of pending PRs, as otherwise things like this keep happening, where work conflicts and we need to keep rebasing. |
please ask for a specific PR on zulip #reviews stream. Most of us spend free/unpaid time on maintenance napari and it is easy to lose some PR. |
Sorry if I made you feel you were not doing enough, I know the feeling and I am doing my best to also help unblock by reviewing/rebasing fixing trivial mistake in CI. |
Hi all, sorry for the delay, I've been on vacation and just got back. It looks like @Czaki was advocating for more GUI test coverage, would you still like this prior to merge (since it will further delay the bugfix)? Also are there any opinions on moving some of the symbol rendering to |
I think we're fine without gui-specific tests... The think we should make sure we test is that if someone changes something elsewhere we don't suddenly lose some of this stuff. |
This PR mainly changes GUI code. And as it is not covered, then the core-dev who accepts it needs to perform manual testing. I may find time for this during weekend. |
Hi @Czaki, I wanted to check if you've had an opportunity to give this a test and/or if you still would like to see GUI tests in this PR! |
|
Note that on
|
Ok it seem for whatever reason my local install was not picking up the newer App-Model and it does work. I've found another bug though, I can't assign the |
yes please, if im understanding correctly, you want to set the shortcut as
@jaimergp I am super stressed/busy right now so any help with the GUI tests would be greatly appreciated! |
Just checked and this works locally once app-model is updated. Alt-E is a problem but Cmd-Alt-E is not, and Alt-E is also a problem on main, so I suggest we merge this. (Optionally after merging in @Czaki's suggestion of changing list to set.) While typing it shows "Meta-E" or "Meta-Alt-E", it would be cool if the Mac-native symbols appeared while typing but that can be updated later imho. @Czaki I also think this should go in 0.4.18, I've added the milestone accordingly, but of course you can modify it if you disagree. |
@jni For me, this PR does that: #5064 but I'm not sure how it interacts with this one.
This PR fixes issue related to #5103 which has 0.5.0 milestone, so that one would also need back porting... |
If you backport a lot, I can remind you of my backport bot |
but I do not backport anything related to app model keys. |
This PR addresses bugs where the improper symbols would be displayed for e.g. ⌘V on Macs, as well as improper capturing on Macs where e.g. Control would be read as Meta and vice versa. This relies on an upstream fix in `app-model` and uses the logic there to properly capture the correct modifier keys, regardless of if Qt is switching Control with Meta or not. fixes napari#5047 fixes napari#5332 fixes napari#5579 depends on pyapp-kit/app-model#82
This PR addresses bugs where the improper symbols would be displayed for e.g. ⌘V on Macs, as well as improper capturing on Macs where e.g. Control would be read as Meta and vice versa. This relies on an upstream fix in
app-model
and uses the logic there to properly capture the correct modifier keys, regardless of if Qt is switching Control with Meta or not.fixes #5047
fixes #5332
fixes #5579
depends on pyapp-kit/app-model#82