-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Context Menu for snapping view to primary axis planes in 3D plots #30976
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
base: main
Are you sure you want to change the base?
Conversation
0ae13f4 to
5417d95
Compare
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.
This is a lot more cleanly implemented than I thought it would require!
I can see context menus being useful in quite a few use cases, we should talk on the dev team about designing these with some thought to it. It may also be worth implementing a base class for this, but I think this is fine for now as a starting point.
@timhoffm in the original issue mentioned compatibility with our event architecture, which I don't know enough to comment on.
I played around with this locally on a qtagg backend, and things work largely as expected:
- The menu works and each option correctly snaps to the expected view
- Long presses on a touchscreen work the same as a mouse right-click to bring up the menu
- With multiple subplots, the action is only applied to the subplot that was clicked on
- Right clicking in a 2D subplot has no effect
- Rotating, panning, and zooming still all work as expected with either the mouse or toolbar buttons
One minor issue that would be nice to fix but isn't blocking, is that if you bring up the menu and then drag the figure window to a new position, the popup does not follow the window.
For documentation, this behavior should get a doc/release/next_whats_new entry, as well as explanation with a screenshot in https://matplotlib.org/stable/users/explain/figure/interactive.html
We should also add tests for this. Ideally for selecting each option, but at the least for opening the menu on each backend.
| self.view_init(elev=elev, azim=azim) | ||
| canvas.draw_idle() | ||
|
|
||
| canvas.manager.context_menu( |
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.
This should check for the existence of the context_menu for the backend to avoid errors:
if hasattr(canvas.manager, 'context_menu'):
canvas.manager.context_menu(event, labels=..., actions=...)| rect.width = 1 | ||
| rect.height = 1 | ||
| popover.set_pointing_to(rect) | ||
| popover.popup() |
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.
My GTK is rusty, but I believe this should be marked for cleanup when closed:
...
popover.connect('closed', lambda p: p.unparent())
popover.popup()| menu.append(item) | ||
| item.connect('activate', lambda _, a=action: a()) | ||
| item.show() | ||
| menu.popup_at_pointer(event.guiEvent) |
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.
Similarly for gtk3:
...
menu.connect('selection-done', lambda m: m.destroy())
menu.popup_at_pointer(event.guiEvent)|
If matplotlib itself starts to use context menus, then the design needs to be careful to allow developers that embed matplotlib widgets into their own GUIs to add their own context actions (something that I do fairly regularly, and which I would have to redesign if it started to conflict with builtin menus). There's likely many ways to design the API, but based on my own usage it could e.g. look like canvas.add_context_menu_entry("group", "name", callback, condition=lambda e: True)where "name" is what gets displayed in the menu, "group" allows grouping entries (with menu separators? or with submenus?), callback is the callback (taking the button_press_event as parameter) and condition is a function taking the button_press_event as argument and returning whether this entry should be displayed (e.g., for the use case here it would allow displaying the menu entries only when over a 3D axes). |
PR summary
closes #23544
This PR introduces a feature that adds context menu on 3d Axes triggered by right-click of the mouse.
Added
context_menu()in Figure Manager that takes arguments, a list of labels and a list of corresponding functions to execute upon selection.Modified
_button_release()to callcanvas.manager.context_menu()with functions for setting orthographic views when the right-click is released on the mouse without moving it significantly. Mouse movement is handled in_on_move()using a small threshold because previously I observed trackpad (on macOS) reported micro-movements during a static click, which falsely flagged the action as "drag" and blocked the menu in specific backends.Backends
tk.Menuimplementation.QtWidgets.QMenuimplementation.wx.MenuandPopupMenu.Gtk.Menu.Gtk.PopoverMenuandGio.Menu.PR checklist