viewport: local_viewport() opt-out of root-viewport inheritance; list_item: height/font_size builders
Some checks failed
CI / build + test (push) Has been cancelled
CI / cargo audit (push) Has been cancelled

`Viewport::local_viewport()` resolves the child's viewport-relative (vw / vh / vmin) and fluid Lengths against the viewport's own rect instead of the root layout viewport the sub-canvas inherits since the fluid-resolution inheritance change. That inheritance is right for scroll-like clips (content renders the same size inside and outside), but it is exactly wrong for a fixed-size floating mini-UI — crustace's phone-shaped quick-settings pill pinned to a corner of a desktop-wide surface resolved its vw text and fluid stock geometry against the whole monitor, inflating the content past the pill's fixed clip and cutting off the bottom stripe. The flag pins the sub-canvas's layout viewport to its own size via the new crate-internal Canvas::set_local_layout_viewport, nested sub-canvases keep propagating the pinned value, and a unit test covers the override plus propagation.
`ListItem::height( impl Into<Length> )` and `ListItem::font_size( impl Into<Length> )` mirror the Toggle / Radio height() builders: override the theme row height (floored at the label's rendered height so the text never clips) and the primary-label font size (subtitle and trailing keep their theme sizes), letting dense context menus trade the stock touch-target generosity for row density.
Docs: widgets.md gains both builder sets, architecture.md documents the layout-viewport inheritance model next to the per-canvas density it parallels, the cookbook slide-in panel recipe notes when the pill needs local_viewport(), and the toggle / radio height() rustdoc demotes its private theme::HEIGHT link to a code span so cargo doc is warning-free again. CHANGELOG entries added.
This commit is contained in:
2026-08-02 13:38:16 +02:00
parent 4247613bb0
commit e343142347
10 changed files with 118 additions and 13 deletions

View File

@@ -296,6 +296,22 @@ impl Canvas
}
}
/// Pin this canvas' layout viewport to its own pixel size, opting a
/// sub-canvas out of the root-viewport inheritance: viewport-relative
/// and fluid [`Length`]s drawn on it resolve against the canvas rect
/// itself. For fixed-size floating mini-UIs (a phone-shaped panel on
/// a desktop surface) whose content must not scale with the surface
/// hosting them.
pub( crate ) fn set_local_layout_viewport( &mut self )
{
let ( w, h ) = self.size();
match self
{
Canvas::Software( c ) => c.layout_viewport = Some( ( w as f32, h as f32 ) ),
Canvas::Gles( c ) => c.layout_viewport = Some( ( w as f32, h as f32 ) ),
}
}
/// Resolve an explicit [`Length`] in **geometry** space: against
/// [`Self::viewport_layout`], with this canvas' [`Self::density`].
/// Widgets resolve caller-supplied geometry lengths through this so
@@ -974,6 +990,21 @@ mod viewport_tests
assert_eq!( sub.density(), 3.0 );
}
#[ test ]
fn sub_canvas_local_layout_viewport_overrides_inheritance()
{
let _g = crate::TEST_GLOBALS_LOCK.lock().unwrap_or_else( |e| e.into_inner() );
let c = Canvas::new( 1920, 1080 );
let mut sub = c.sub_canvas( 396, 644 );
assert_eq!( sub.viewport_layout(), ( 1920.0, 1080.0 ) );
sub.set_local_layout_viewport();
assert_eq!( sub.viewport_layout(), ( 396.0, 644.0 ) );
// Nested sub-canvases keep propagating the pinned local viewport.
let nested = sub.sub_canvas( 200, 200 );
assert_eq!( nested.viewport_layout(), ( 396.0, 644.0 ) );
}
#[ test ]
fn font_px_is_constant_physical_in_physical_mode()
{