cmd_actions.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. from PySide6.QtGui import QAction
  2. from PySide6.QtWidgets import QMenu
  3. from .active_suite import spec as active_suite
  4. def add_cmd_actions_to_menu(parent, receiver, api, menu=None, cmdkwargs=None):
  5. """Slot to populate (connected) QMenu with dataset actions
  6. Actions' `triggered` signal will be connected to a `receiver` slot.
  7. Typical usage is to connect a QMenu's aboutToShow signal to this
  8. slot, in order to lazily populate the menu with items, before they
  9. are needed.
  10. If `menu` is `None`, the sender is expected to be a QMenu.
  11. """
  12. if menu is None:
  13. menu = parent.sender()
  14. group_separator = menu.addSeparator()
  15. # generate a submenu for each unique group specification
  16. # across all commands in the dataset API
  17. submenus = {
  18. group: QMenu(group, parent=menu)
  19. for group in set(
  20. cmdspec['group'] for cmdspec in api.values()
  21. if 'group' in cmdspec
  22. )
  23. }
  24. for cmdname, cmdspec in api.items():
  25. # we create a dedicated action for each command
  26. action = QAction(cmdspec.get('name', cmdname), parent=parent)
  27. # the name of the command is injected into the action
  28. # as user data. We wrap it in a dict to enable future
  29. # additional payload
  30. adata = dict(__cmd_name__=cmdname, __api__=api)
  31. # put on record, if we are generating actions for a specific
  32. # dataset
  33. if cmdkwargs is not None:
  34. adata.update(cmdkwargs)
  35. action.setData(adata)
  36. # all actions connect to the command configuration
  37. # UI handler, such that clicking on the menu item
  38. # brings up the config UI
  39. action.triggered.connect(receiver)
  40. # add to menu
  41. # sort and group actions by some semantics
  42. # e.g. all commands from one extension together
  43. # to avoid a monster menu.
  44. # if the menu lookup knows a better place to put a command
  45. # based on the command interface class, it will be used
  46. # instead of the main menu
  47. target_menu = submenus.get(cmdspec.get('group'), menu)
  48. target_menu.addAction(action)
  49. for group, submenu in sorted(
  50. submenus.items(),
  51. # sort items with no sorting indicator last
  52. key=lambda x: active_suite.get('api_group_order', {}).get(
  53. x[0], ('zzzz'))):
  54. # skip menus without actions
  55. if not submenu.actions():
  56. continue
  57. menu.insertMenu(group_separator, submenu)