Skip to content

Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, separators, position, width)#233

Open
fyoosh wants to merge 4 commits into
pgaskin:masterfrom
fyoosh:feat/menu-main-caret
Open

Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, separators, position, width)#233
fyoosh wants to merge 4 commits into
pgaskin:masterfrom
fyoosh:feat/menu-main-caret

Conversation

@fyoosh

@fyoosh fyoosh commented Jun 10, 2026

Copy link
Copy Markdown
PR upstream NickelMenu

Summary

On firmware 4.23.15505+, where the original main menu was removed, NickelMenu builds its menu from scratch as a bare NickelTouchMenu. Stock Nickel popovers (e.g. the brightness and battery popovers) draw a pointer caret aimed at their anchor, sit inset from the screen edge, and use full-width dividers — the from-scratch menu has none of that. This adds a handful of opt-in experimental: options to bring it closer to the native look.

Everything here defaults to the current behaviour, so an unset config renders exactly as before (the left screenshot above is this branch with no options set).

Options added

All under the existing menu_main_15505_* experimental namespace:

Option Effect
caret draw the native popover caret, aimed at the NickelMenu tab
decoration caret edge (0 top, 3 bottom; 1/2 the side edges, 5 none)
caret_dx / caret_dy nudge the caret anchor
offset_x / offset_y nudge the popup position (e.g. a screen-edge margin)
width fixed popover width (default auto-size)
flush_separators full-width dividers via Nickel's own separator
separator_inset inset for the above, to line up with the painted border
italic 0 renders item labels upright

Notes on the implementation

A few things were needed beyond what the existing code does, in case they're useful context for review:

  • The caret only paints if the menu has a parent (drawDecoration returns early
    otherwise), showDecoration(true) is set (gated in paintEvent), and a target
    rect is given — so the menu is now parented to the tab button's window when the
    caret is requested.
  • offset_x/_y are applied with move() after popup(), because popup()'s
    screen-fit clamping otherwise swallows them.
  • flush_separators adds a LightMenuSeparator and widens it after layout,
    since the menu insets every action.
  • italic 0 calls MenuTextItem::setTextItalics(false) after setText()
    (the constructor flag alone doesn't stick, as setText re-applies italics).

The four new NickelTouchMenu/MenuTextItem symbols are resolved optionally, so
firmware without them just falls back to the current appearance.

Testing

Built with nickeltc:1.0 and verified on a Kobo Libra Colour, FW 4.45.23697.
Symbol tags follow the existing entries (4.23.15505 *); CI will confirm across
versions.

A question on defaults

I've kept everything opt-in here to stay conservative — but I wanted to raise one idea:

The pointer/caret and full-width dividers are arguably less "a styling option" and more "the native Kobo look this menu is currently missing".

NickelMenu's menus look native because they are native widgets, and the 15505+ popover is the one element that doesn't (flat box, inset dividers, no caret/pointer) only because it's built from scratch rather than reused.

So — would you want the caret, full-width dividers, and a small edge margin on by default for the 15505+ menu, with width / italic staying opt-in? The caret anchor is derived from the tab button's own geometry, so it's device-independent, and the margin is just a small fixed inset; width and italic are the user-taste parts, which I'd suggest stay opt-in regardless.

No presumption either way — happy to leave it fully opt-in as in this PR, flip those to default, or whatever fits your appetite for a behaviour change. The "match native" angle just felt worth raising.

Thanks for your work on NickelMenu so far :)

Disclosure: I developed this with Claude Code (also noted in the commit
trailers). The reverse-engineering, build, and on-device testing were all
verified on hardware, and I'm happy to walk through any of it in review.

fyoosh and others added 4 commits June 10, 2026 14:03
The from-scratch main menu on FW 4.23.15505+ renders as a plain
rectangle, unlike every stock Nickel popover, which draws a caret
pointing at its anchor. NickelTouchMenu has the full decoration API;
it just needs three things NickelMenu never did:

- a parent widget: drawDecoration() returns immediately when the
  menu has no QObject parent, so the caret can never render on the
  stock nullptr-parent construction (this is why the menu has always
  been flat). Parent to the tab button's top-level window, whose
  coordinate space the anchor mapping expects. The nullptr parent is
  kept when the caret is not requested.
- showDecoration(true): paintEvent() gates drawDecoration() on this
  flag.
- setDecorationPositionOffset(): the global anchor point the caret
  aims at (the painter adds half the target rect's width itself, so
  pass the target's top-left).

All new behavior is opt-in via experimental options and defaults to
the existing appearance:

- menu_main_15505_caret      draw the native caret (default off)
- menu_main_15505_decoration caret edge: 0=top 1=right 2=left
                             3=bottom 5=none (default 3)
- menu_main_15505_caret_dx/_dy  nudge the caret anchor (px)
- menu_main_15505_offset_x/_y   nudge the popup position (px)

The four NickelTouchMenu symbols are resolved optionally, so firmware
without them degrades to the current flat menu.

Verified on a Libra Colour, FW 4.45.23697, NickelMenu v0.6.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fitting

The stock popup point (derived from the tab button's geometry) lands far
off-screen right, so QMenu::popup()'s screen-fit clamping repositions the
menu every time — and silently swallows any offset added to the popup
point itself. Apply menu_main_15505_offset_x/_y via move() after popup()
instead: the offsets become relative to the position the menu actually
landed at, which also makes them device-geometry independent.

Verified on a Libra Colour, FW 4.45.23697: offset_x -30 / offset_y -16
inset the popover from the screen edge and bottom bar like the stock
toolbar popovers, with the caret staying anchored to the tab button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
menu_main_15505_width sets a fixed popover width in pixels; unset/0
keeps the stock auto-size-to-widest-item behaviour. Auto-sizing tracks
the longest configured label, so menus with short labels render
narrower than the stock Nickel popovers; a fixed width lets the menu
match the surrounding UI's proportions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
menu_main_15505_flush_separators draws the popover's row dividers with
Nickel's native separator action (the same LightMenuSeparator the
pre-15505 main menu items use) and stretches them toward the popover
edges after popup() assigns geometry, since the menu lays out every
action inset from the edges. menu_main_15505_separator_inset tunes how
far the dividers stay from the edges so they can be lined up with the
painted border (the widget's true edge sits outside the frame).

menu_main_15505_italic 0 renders item labels upright. The MenuTextItem
constructor's italic flag is not sufficient on its own because
setText() re-applies the item's italics; the explicit
MenuTextItem::setTextItalics(false) after setText() is what sticks
(this mirrors the stock battery popover, which mixes upright labels
with italic tap actions via the same setter).

Both options default to the existing stock-NickelMenu appearance.
Also tones down the debug logging added with the caret work.

Verified on a Libra Colour, FW 4.45.23697.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@fyoosh fyoosh changed the title Add experimental options to style the 15505+ main menu popover (caret, position, width, separators) Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, position, , separators) Jun 10, 2026
@fyoosh fyoosh changed the title Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, position, , separators) Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, separators, width, position) Jun 10, 2026
@fyoosh fyoosh changed the title Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, separators, width, position) Add experimental options to style the 15505+ main menu popover to match stock Nickel (caret, separators, position, width) Jun 10, 2026
@fyoosh fyoosh marked this pull request as ready for review June 10, 2026 18:56
@fyoosh fyoosh requested a review from pgaskin as a code owner June 10, 2026 18:56
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.

1 participant