Skip to content

feat(custom) Implement dropdown menu support for custom modules#71

Open
koshea wants to merge 3 commits intowayle-rs:masterfrom
koshea:feature/custom-mod-dropdowns
Open

feat(custom) Implement dropdown menu support for custom modules#71
koshea wants to merge 3 commits intowayle-rs:masterfrom
koshea:feature/custom-mod-dropdowns

Conversation

@koshea
Copy link
Copy Markdown

@koshea koshea commented Mar 29, 2026

Objective

Enable custom modules to show an inline dropdown picker for context-switching use cases (kubectl, gcloud, etc.) without requiring new Rust code per widget, pure config only.

Solution

Added three new config fields to CustomModuleDefinition:

  • dropdown-list-command — shell command returning newline-separated options
  • dropdown-select-command — shell command run on selection; the chosen item is passed via $WAYLE_SELECTED env var (not string interpolation) to avoid shell injection
  • label-ellipsize — end (default), middle, or start; controls pango truncation mode for both the bar label and dropdown items

left-click = "dropdown" (bare, no colon) opens the module's own inline popover. A new ClickAction::InlineDropdown variant handles parsing; the registry dispatcher treats it as a no-op since the custom module handles it directly.

The dropdown picker (CustomDropdownPicker) follows the existing DevicePicker pattern: ListBox + FactoryVecDeque, single-click activation, checkmark on the active item (matched by exact trimmed text against the module's current output). The popover uses the standard .dropdown wrapper, autohide, position detection, and shadow styling.

A BarButtonInput::SetEllipsize message was added to allow modules to override the label truncation mode without changing BarButtonBehavior.

Additional robustness:

  • Generation counter on dropdown loads discards stale results from rapid toggle cycles
  • Non-interactive (no items) placeholder with disabled styling when the list command returns empty
  • Selection triggers sequential execution: select command (awaited) → main command refresh → immediate label update
  • Dropdown is cleaned up on definition change/removal

Example config:

[[modules.custom]]
id = "kube-context"
command = "kubectl config current-context"
interval-ms = 5000
format = "{{ output }}"
icon-name = "ld-layers-symbolic"
label-max-length = 24
label-ellipsize = "middle"
left-click = "dropdown"
dropdown-list-command = "kubectl config get-contexts -o name"
dropdown-select-command = 'kubectl config use-context "$WAYLE_SELECTED"'

Test Plan

  • Add custom module with dropdown config → dropdown opens with items on click
  • Select an item → select command runs, label refreshes immediately
  • Active item shows checkmark and accent styling
  • label-ellipsize = "middle" with label-max-length → bar label and dropdown items truncate in the middle
  • No dropdown-list-command → left-click = "dropdown" is a no-op
  • Command returns empty → (no items) placeholder shown, non-interactive
  • Rapid toggle while loading → no stale results or duplicate popovers
  • Hot-reload dropdown-list-command → dropdown recreated on next open
  • Hot-reload label-ellipsize → takes effect immediately

@agrahamlincoln
Copy link
Copy Markdown
Contributor

I really liked the idea here, and wanted a similar feature for a custom module that i "hacked" in a dropdown with wofi. I wrote up my own solution for this in #83 that i think is more idiomatic and scalable for other usecases and I considered your kubectl usecase as well to see if my solution would enable you as well. take a look! i'd love to collaborate with you on a solution that works well and is extensible for more/future wayle usecases.

@koshea
Copy link
Copy Markdown
Author

koshea commented Apr 2, 2026

I really liked the idea here, and wanted a similar feature for a custom module that i "hacked" in a dropdown with wofi. I wrote up my own solution for this in #83 that i think is more idiomatic and scalable for other usecases and I considered your kubectl usecase as well to see if my solution would enable you as well. take a look! i'd love to collaborate with you on a solution that works well and is extensible for more/future wayle usecases.

Hi @agrahamlincoln glad to hear I am not the only one who wanted this functionality. I don't have a strong case on whether these should be rolled up into the dropdown registry. They seemed less likely to be re-usable to me hence keeping in the module. Appreciate the other improvements you made and happy to collaborate to get one or the other version merged.

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