ltk: responsive padding/spacing and scrolling, expanded theme palette, and bundled Adwaita cursors
Some checks failed
CI / build + test (push) Has been cancelled
CI / cargo audit (push) Has been cancelled

A mixed pass over the default theme and the layout/input core, plus the toolkit's own cursor set. Grouped by area below.
== Responsive sizing ==
Add `Length::dp( px )` — a "design pixel". It interprets `px` against a configurable reference vmin (default 412 px, the eydos mobile reference width) and returns `Vmin( px / reference * 100 ).clamp( px * 0.7, px * 1.5 )`, so a value authored against a mock-up scales with the surface without collapsing on tiny screens or ballooning on a 4K desktop. The reference is process-global, set via `set_design_reference()` and read via `design_reference()` (stored as f32 bits in an AtomicU32); both are re-exported from `lib.rs`.
Make container and grid insets relative. `Container`'s four padding fields become `Length` instead of `f32`; every setter (`padding`, `padding_h`, `padding_v`, `padding_top`/`right`/`bottom`/`left`) now takes `impl Into<Length>`, so existing `f32` call sites keep compiling via the `From<f32>` shim. The values are resolved against the viewport in `Container::preferred_size` and in the container draw path (`draw/layout.rs`). `WrapGrid`'s `spacing_x`, `spacing_y` and `padding` get the same treatment, with a `resolved( canvas )` helper funnelling the per-frame resolution and `grid()` seeding `Length::px` defaults. Container tests now compare against `Length::px( … )`.
== Scrolling ==
`Scroll::preferred_size` is now axis-aware. A horizontal-only scroll reports its child's natural height rather than claiming all remaining vertical space, so it no longer steals Y from its siblings when it sits inside a `Column`; vertical and both-axis scrolls keep the spacer-like `( max_width, 0.0 )`. `Column`'s space-distribution correspondingly treats a `Scroll` as a vertical space-claimer only when its axis allows Y.
Disambiguate nested scroll viewports by direction. On press the gesture state now collects every scroll viewport under the point (`scroll_candidates`, innermost first) instead of committing to one; on the first 8 px of motion it locks onto the candidate whose axis matches the dominant direction (`scroll_locked`), so a horizontal scroller nested inside a vertical list no longer grabs the wrong axis. The pointer scroll hit test is aligned to the same innermost-first ordering.
== Theme palette ==
`themes/default/theme.json` gains named colours (green / green-deep, yellow, orange / orange-deep, pink / pink-soft, sky-deep, error / error-soft, neutral-tertiary) and new semantic slots in both light and dark modes: `danger`, `text-tertiary`, `accept`, `chip` / `chip-active` / `chip-active-fg`, and `avatar-1` … `avatar-9`.
== Cursors ==
Bundle GNOME's Adwaita cursor theme — the cursors GNOME Shell uses — into `themes/default/cursors/` so a Wayland compositor can draw consistent, complete pointers for ltk applications without the toolkit rasterising cursors itself and without depending on adwaita-icon-theme being installed on the target. The cursors are copied verbatim in XCursor binary format: 35 image files, one per CSS/freedesktop cursor name (default, text, pointer, *-resize, …), plus 27 customary X11 alias symlinks (arrow → default, hand2 → pointer, …); a sibling `cursor.theme` makes the tree a valid XCursor theme. The existing `ltk-theme-default.install` copies `themes/default` recursively, so the directory ships with no packaging change. Applications keep declaring a `CursorShape` per widget over `wp_cursor_shape_v1`; the compositor resolves it against the active theme's `cursors/` directory by name, and the set covers all 34 `CursorShape` variants.
Document the set in `themes/default/cursors/README.md` (what it is, the XCursor layout, the full shape list, how the compositor consumes it, guidance for forks) and `themes/default/cursors/LICENSE.md` (attribution and licence options, modelled on the icons catalogue LICENSE). `lib.rs` lists the cursors in its third-party-assets section.
Close out licensing in `debian/copyright`: a `Files: themes/default/cursors/*` paragraph records the upstream dual offer (CC-BY-SA-3.0 or LGPL-3, and CC-BY-SA-4.0 for the newer assets) attributed to the GNOME Project, with standalone CC-BY-SA-3.0, CC-BY-SA-4.0 and LGPL-3 paragraphs (summary-plus-canonical-URL for the CC licences, matching the existing CC-BY-4.0 entry; LGPL-3 referencing /usr/share/common-licenses/LGPL-3). The files are unmodified from upstream, so there is nothing to declare under the ShareAlike "indicate if changes were made" clause.
Add `tests/cursor_assets.rs`: every `CursorShape` name resolves to a valid XCursor file (Xcur magic, following symlinks), `cursor.theme` is present, no entry is a dangling symlink, and the expected-name list stays in sync with the enum's 34 variants.
This commit is contained in:
2026-05-28 23:11:14 +02:00
parent 3d8523533c
commit 9ca3b60f3a
78 changed files with 570 additions and 102 deletions

View File

@@ -0,0 +1,73 @@
# Default theme cursors
This directory holds the pointer cursors for the ltk **default** theme.
They are GNOME's **Adwaita** cursors (what GNOME Shell uses), bundled
verbatim so the theme is self-contained and does not depend on
`adwaita-icon-theme` being installed on the target system.
Licence and attribution are documented separately in
[`LICENSE.md`](./LICENSE.md).
## Layout
Standard XCursor theme layout:
```
themes/default/
├── cursor.theme # XCursor theme manifest (Name=Default)
└── cursors/
├── default # one binary XCursor file per CSS cursor name
├── text
├── pointer
├── ew-resize
├── …
├── arrow -> default # customary X11 alias symlinks
└── hand2 -> pointer
```
- Each regular file is a binary XCursor image set (magic `Xcur`),
carrying one or more nominal sizes and, for the busy cursors, several
animation frames.
- The file **name is the CSS / freedesktop cursor name** (`default`,
`text`, `pointer`, `not-allowed`, `ns-resize`, …), which is exactly
the name a `wp_cursor_shape_v1` shape resolves to. The alias symlinks
(`arrow`, `hand2`, `bottom_left_corner`, …) are the legacy X11 names;
they are not required by the cursor-shape protocol but are kept so the
tree also works as a plain XCursor theme (e.g. for XWayland).
## Cursor set
The theme provides a file for every shape ltk can request — the 34
variants of [`ltk::CursorShape`](../../../src/types.rs), which mirror
`cursor_icon::CursorIcon` 1:1:
`default`, `context-menu`, `help`, `pointer`, `progress`, `wait`,
`cell`, `crosshair`, `text`, `vertical-text`, `alias`, `copy`, `move`,
`no-drop`, `not-allowed`, `grab`, `grabbing`, `e-resize`, `n-resize`,
`ne-resize`, `nw-resize`, `s-resize`, `se-resize`, `sw-resize`,
`w-resize`, `ew-resize`, `ns-resize`, `nesw-resize`, `nwse-resize`,
`col-resize`, `row-resize`, `all-scroll`, `zoom-in`, `zoom-out`.
`wait` and `progress` are animated (multiple frames with per-frame
delays). The `tests/cursor_assets.rs` integration test enforces that
every name above resolves to a valid XCursor file.
## How they are used
ltk does **not** rasterise cursors itself; as a Wayland client it
declares a shape per widget through `wp_cursor_shape_v1` and the
compositor draws it. The Liberux compositor (forge) resolves the
requested shape against the active theme's `cursors/` directory by CSS
name, picks the image whose nominal size is closest to `24px × output
scale`, and uploads it at the cursor's hotspot — so these files are what
the user actually sees under forge. A compositor that does not advertise
`wp_cursor_shape_v1`, or that uses a different cursor theme, will ignore
this directory.
## Forking / overriding
To ship different cursors in a derived theme, drop replacement XCursor
files (same CSS names) into the fork's `cursors/` directory. Keep
`cursor.theme` so the tree stays a valid XCursor theme, and update the
`Files: themes/default/cursors/*` paragraph in `debian/copyright` plus
this directory's `LICENSE.md` to match the new source and licence.