Repository navigation
ContextMenu
A right-click menu with icons, shortcut hints, danger and disabled items, separators and submenus. It isn't mounted in a cell: it opens at the pointer.
from wapyt import ContextMenu, ContextMenuConfig, MenuItem
menu = ContextMenu(ContextMenuConfig(items=[
MenuItem("open", "Open", "mdi-open-in-new", shortcut="Enter"),
MenuItem("rename", "Rename", "mdi-pencil", shortcut="F2"),
MenuItem("share", "Share", "mdi-share-variant", items=[
MenuItem("copy_link", "Copy link", "mdi-link"),
MenuItem("email", "Email…", "mdi-email-outline"),
]),
MenuItem(separator=True),
MenuItem("delete", "Delete", "mdi-delete", danger=True, shortcut="Del"),
], label="File"))
menu.attach("#files", context="files")
menu.on_select(lambda p: self.on_file_action(p["id"], p["target"]))<ul id="files">
<li data-context="r1">report.pdf</li>
<li data-context="r2">photo.png</li>
</ul>MenuItem(id, label, icon, shortcut, danger, disabled, items, separator, checkable, group, checked)
| Field | |
|---|---|
id |
Reported by on_select; used by hide / disable. Unique across the whole menu, submenus included |
label, icon
|
Text (defaults to the id) and an MDI class |
shortcut |
A hint on the right ("Ctrl+C"). Display only: the menu doesn't bind the key |
danger |
Destructive styling |
disabled |
Shown but not choosable |
items |
A submenu; the item opens it instead of being chosen |
separator=True |
A divider (every other field is ignored) |
checkable, checked
|
A tick that flips when chosen (role="menuitemcheckbox") |
group, checked
|
One of a radio group: choosing it checks it and unchecks the others (role="menuitemradio") |
Separators that would lead, trail or double up after hiding items are dropped automatically.
attach(target, context=None) opens the menu over an element (a CSS
selector or element) on right-click, Shift+F10 or the Menu key.
context comes back in every payload. target in the payload is the
data-context attribute of the nearest ancestor of the click that has one,
so one menu attached to a list knows which row was clicked. detach(target)
removes it.
show_at(x, y, context=None, target=None, hide=[], disable=[]) opens it at
viewport coordinates from your own handler, e.g. event.clientX /
event.clientY in a contextmenu listener. hide and disable list item ids
to drop or grey out for this opening only, for per-row permissions:
def on_row_menu(self, event, row):
event.preventDefault()
self.menu.show_at(event.clientX, event.clientY, context=row["id"],
hide=[] if row["can_share"] else ["share"],
disable=["delete"] if row["locked"] else [])Only one menu is open on a page at a time; opening another closes it.
| Method | Payload |
|---|---|
on_select |
{id, context, target}, plus checked (the new state) for checkable and group items |
on_show |
{context, target} |
on_hide |
{context, target}, whether chosen or dismissed |
Following the WAI-ARIA menu pattern:
- Focus moves into the menu when it opens.
- ↑/↓ move and wrap; Home and End jump to the ends.
- Enter or Space chooses.
- → opens a submenu and ← closes it.
- Escape closes the innermost menu; Tab closes everything.
- Focus returns to where it was.
Disabled items can be focused but not chosen.
Clicking outside, scrolling or resizing the window also closes the menu. Its position is kept inside the viewport, and submenus open to the left when there's no room on the right.
hide(), is_open(), set_items(items), destroy().
Added in #44. Unlike show_at(hide=, disable=), which applies
to one opening, these persist:
| Method | |
|---|---|
set_disabled(ids, disabled=True) |
False enables items, even ones declared disabled
|
set_hidden(ids, hidden=True) |
|
set_checked(id, checked=True) |
Without firing on_select; checking a group item unchecks the rest |
is_disabled, is_hidden, is_checked
|
For a menu bar across the top of the app, see MenuBar.
Tree, DataTable and Terminal use ContextMenu for their right-click menus,
keeping TreeAction / TableAction as their API.
ContextMenuConfig(extra={"menuClass": "my-menu", "itemClass": "my-item"}) adds
class names beside the wapyt-cmenu ones, e.g. for test selectors or your own
CSS. (The built-in widgets also set per-item data-* attributes from
JavaScript; MenuItem doesn't expose that.)
wapyt is MIT-licensed · Repository · pyTincture · Issues
Getting started
Widgets
- Layout and MainWindow
- Tree
- DataTable
- Form
- ModalWindow
- Window
- TabWidget
- Toolbar
- Sidebar
- Chat
- Terminal
- CardPanel
- ResourceBoard
- File Transfer
- Message
- ContextMenu
- MenuBar
- Listbox
- Kanban
- ProgressBar
- Pagination
- Popup and tooltips
- Chart
- Scheduler
- MediaPlayer
Guides
Planning
Contributing