Skip to content

a right-click menu wherever a track or a browse item is shown - #14

Merged
2 commits merged into
Ryoku-dev:mainfrom
eximora-private:feat/right-click-menu
Oct 21, 2026
Merged

2 commits merged into
Ryoku-dev:mainfrom
eximora-private:feat/right-click-menu

Conversation

@eximora-private

Copy link
Copy Markdown

The queue had no context menu at all. Moving a queued track into a playlist meant liking it first, opening Liked Songs and using the menu there, which someone in the Discord called inconsistent as hell and is hard to argue with. The cards on Home, Search and the library had none either, and neither did the playing track in the bar or the rows under "Recently played".

Every surface that shows a track or a browse item now answers a right-click through the one Menu the track lists already use:

Surface What it offers
Queue rows the track menu, with "Remove from queue"
The playing row in the queue the same, without the removal
Cards (CardGrid, Shelf) a song gets the track menu; an album, artist or playlist gets Play, Open, Add to shortcuts
"Recently played" rows the same, by what the row is
The playing track in the player bar and the mini window the track menu

A song card and a playlist card are not the same thing, so ItemMenu decides by kind and takes the host's own play and open functions rather than carrying a second copy of them.

Three things that came out of building it

"Play next" on the track that is already playing does nothing. Neither does "Add to queue". They are left out there rather than offered and ignored, which Menu works out for itself by comparing against Playback.now.

The menu did not close when you clicked somewhere else. It lived inside the list that opened it, so its dismiss layer only covered that list. It now lives on the window content item, which also means a list with clip: true can no longer cut the panel off.

A menu opened near the bottom of the window hung off the edge. openAt read panel.height to decide whether to flip above the press, but the height follows the items the song produces and is not known at that moment. The placement is a binding on the panel instead. The player bar is at the bottom of the window, so it needed this every single time.

And one that took two tries

Scrolling with the menu open leaves it hanging over a row that has moved on, so the wheel closes it. That did nothing at first: WheelHandler is the one pointer handler Qt narrows to PointerDevice.Mouse, and the Wayland plugin stamps wheel events with the seat's primary pointing device, which on this machine is reported as a touchpad although there is no touchpad in it. PlayerBar and HomeFeed already name both devices for exactly that reason; the new handler did not, and failed silently.

Verified

Driven on a running client built from this branch: the queue rows, the card shelves on Home, the "Recently played" rows, the playing track in the player bar (flipping up, inside the window), the menu closing on a click elsewhere, and the playing track showing no queue actions.

Not exercised on screen: the mini window, which did not map a window in my session. Its wiring is the same four lines as the player bar's.

Search results, the library tabs and the command palette are untouched; they looked like a separate decision about what belongs in each.

The queue had no context menu at all, so moving a queued track into a
playlist meant liking it first, finding it in Liked Songs and using the
menu there. The cards on Home, Search and the library had none either,
and neither did the playing track in the bar.

Every surface now answers a right-click through the one Menu the lists
already use:

- queue rows, with "Remove from queue"; the playing row keeps the menu
  but not the removal, since the queue cannot drop the track out from
  under itself
- cards, through CardGrid and Shelf. A song card gets the track menu; an
  album, artist or playlist is not a track, so it gets Play, Open and Add
  to shortcuts, run through the card's own logic
- the playing track in the player bar and in the mini window

Three things came out of doing it:

"Play next" and "Add to queue" are a no-op on the track that is already
playing, so they are left out there rather than offered and ignored.

The menu lived inside the list that opened it, so its dismiss layer only
covered that list: a click anywhere else left the menu standing. It now
lives on the window, which also means a list with clip: true can no
longer cut the panel off.

openAt read panel.height to decide whether to flip the menu above the
press, but the height follows the items the song produces and is not
known at that moment. The placement is a binding on the panel instead,
so a menu opened near the bottom of the window lands inside it. That is
what the player bar needs every single time.
"Recently played" on Home is a list of browse items like the shelves, so
it answers a right-click the same way. That made the block deciding what
an item is a third copy, so it moved into ItemMenu: the host hands it its
own play and open functions and the component picks the track menu for a
song and Play / Open / Add to shortcuts for anything else.

The wheel closing the menu did not work. WheelHandler is the one handler
Qt narrows to PointerDevice.Mouse, and the Wayland plugin stamps every
wheel event with the seat's primary pointing device, which is reported as
a touchpad on a machine with no touchpad in it. PlayerBar and HomeFeed
already name both devices for that reason; this one did not.
@neur0map neur0map closed this pull request by merging all changes into Ryoku-dev:main in a1510fb Oct 21, 2026
@neur0map

Copy link
Copy Markdown
Member

Merged, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants