diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fcd784..589ae8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ All notable changes to `ltk` are documented here. The format is based on [Keep a - **Renamed** `set_design_reference` / `design_reference` → `set_fluid_reference` / `fluid_reference`. **`Length::dp` changed meaning** — it used to be a surface-proportional value, and that behaviour now lives on `Length::fluid`; `dp` is the constant-physical-size unit. - **Widget struct fields are now `pub( crate )`** (configured through builders), except the value / state types apps read or construct (`Time`, `Date`, `ComboState`). +### Fixed + +- **Content inside a `scroll` no longer renders smaller than the rest of the surface.** Scroll viewports draw their child into a sub-canvas sized to the viewport rect, and fluid `Length` resolution (`Canvas::geom_px` / `font_px` — icon sizes, row heights, paddings, font sizes) resolved against that smaller canvas instead of the surface, shrinking everything inside any scroll by the width ratio (~13 % in a 360 px window with 24 px margins). Sub-canvases now inherit the root canvas's layout viewport (`viewport_layout` / `viewport_logical`), propagated through nested sub-canvases, so geometry resolves identically inside and outside offscreen content. + ## [0.2.0] — 2026-06-25 This release adds the primitives an embedder needs to drive ltk as the render backend for a retained, externally-owned widget tree (for example projecting an Android view hierarchy onto an ltk surface). Each is kept general rather than tied to one consumer. diff --git a/src/gles_render/mod.rs b/src/gles_render/mod.rs index 782272e..2114e51 100644 --- a/src/gles_render/mod.rs +++ b/src/gles_render/mod.rs @@ -151,6 +151,12 @@ pub struct GlesCanvas /// falls back to [`Self::font`]. pub font_registry: Option>, pub dpi_scale: f32, + /// Layout-resolution viewport inherited from the parent canvas. + /// `None` on a root canvas (resolve against own size); sub-canvases + /// carry the root surface size so fluid geometry and fonts resolve + /// the same inside offscreen content (scroll viewports, clip layers) + /// as outside it. + pub( crate ) layout_viewport: Option<( f32, f32 )>, pub global_alpha: f32, pub width: u32, pub height: u32, diff --git a/src/gles_render/setup.rs b/src/gles_render/setup.rs index 99b3744..273c404 100644 --- a/src/gles_render/setup.rs +++ b/src/gles_render/setup.rs @@ -336,6 +336,7 @@ impl GlesCanvas font_face, font_registry: None, dpi_scale: 1.0, + layout_viewport: None, global_alpha: 1.0, width, height, @@ -547,6 +548,8 @@ impl GlesCanvas font_face: self.font_face, font_registry: self.font_registry.as_ref().map( Arc::clone ), dpi_scale: self.dpi_scale, + layout_viewport: Some( self.layout_viewport.unwrap_or( + ( self.width as f32, self.height as f32 ) ) ), global_alpha: self.global_alpha, width, height, diff --git a/src/render/mod.rs b/src/render/mod.rs index a1c5e37..f5968a9 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -137,6 +137,12 @@ pub struct SoftwareCanvas pub font_registry: Option>, /// DPI scale factor applied to font sizes. pub dpi_scale: f32, + /// Layout-resolution viewport inherited from the parent canvas. + /// `None` on a root canvas (resolve against own size); sub-canvases + /// carry the root surface size so fluid geometry and fonts resolve + /// the same inside offscreen content (scroll viewports, clip layers) + /// as outside it. + pub( crate ) layout_viewport: Option<( f32, f32 )>, /// Global alpha multiplier for all drawing operations (0.0 = /// transparent, 1.0 = opaque). pub global_alpha: f32, @@ -216,13 +222,21 @@ impl Canvas /// ``` pub fn viewport_logical( &self ) -> ( f32, f32 ) { - let ( pw, ph ) = self.size(); + let ( pw, ph ) = match self.layout_viewport() + { + Some( ( w, h ) ) => ( w, h ), + None => + { + let ( w, h ) = self.size(); + ( w as f32, h as f32 ) + } + }; let scale = self.dpi_scale(); if scale > 0.0 { - ( pw as f32 / scale, ph as f32 / scale ) + ( pw / scale, ph / scale ) } else { - ( pw as f32, ph as f32 ) + ( pw, ph ) } } @@ -235,10 +249,21 @@ impl Canvas /// by `dpi_scale` at raster time, so they must NOT use this. pub fn viewport_layout( &self ) -> ( f32, f32 ) { + if let Some( v ) = self.layout_viewport() { return v; } let ( pw, ph ) = self.size(); ( pw as f32, ph as f32 ) } + /// Inherited layout viewport, when this is a sub-canvas. + fn layout_viewport( &self ) -> Option<( f32, f32 )> + { + match self + { + Canvas::Software( c ) => c.layout_viewport, + Canvas::Gles( c ) => c.layout_viewport, + } + } + /// Resolve a stock-widget **geometry** design pixel (height, padding, /// box size, gap…) through the process-wide [`crate::WidgetScaling`] /// mode, into a concrete physical-pixel value for the layout tree. diff --git a/src/render/setup.rs b/src/render/setup.rs index 697ae72..12ea198 100644 --- a/src/render/setup.rs +++ b/src/render/setup.rs @@ -36,6 +36,7 @@ impl SoftwareCanvas font_face: handle.face, font_registry: None, dpi_scale: 1.0, + layout_viewport: None, global_alpha: 1.0, glyph_cache: HashMap::new(), clip_mask: None, @@ -54,6 +55,8 @@ impl SoftwareCanvas font_face: self.font_face, font_registry: self.font_registry.as_ref().map( Arc::clone ), dpi_scale: self.dpi_scale, + layout_viewport: Some( self.layout_viewport.unwrap_or( + ( self.pixmap.width() as f32, self.pixmap.height() as f32 ) ) ), global_alpha: self.global_alpha, glyph_cache: HashMap::new(), clip_mask: None,