# Changelog All notable changes to `ltk` are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added - **Responsive sizing system** with two selectable modes via `WidgetScaling` (`Fluid` / `Physical`; `set_widget_scaling` / `widget_scaling`, default `Fluid`). New `Length` constructors — `orient( portrait, landscape )` (a percentage of the width in portrait, of the height in landscape), `fluid( px )` (surface-proportional, calibrated against `set_fluid_reference` and bounded by `FLUID_MIN` / `FLUID_MAX`), `dp( px )` (constant physical size scaled by `set_density` / `density`), and `widget( px )` (picks fluid or dp per the active mode). `Canvas::geom_px` (geometry, physical layout space) and `Canvas::font_px` (font, bridging the logical / physical split per mode) give widgets and apps one resolution path. - **`Button::font_size` / `height` / `width`** and **`TextEdit::height`** builders, all `impl Into`, so control boxes scale with the surface. `Text::line_height( mult )` opens the gap between wrapped lines. `Separator::pad_v` (with `Length::px( 0.0 )` for a flush divider). - **Performance guardrails**: opt-in diagnostics via `LTK_PERF_WARN=1` (stuck animation, sustained software-render animation, low `poll_interval`) and a ~30 Hz software-animation cap overridable with `App::cap_software_animation`. - **`test-support` Cargo feature** gates the `test_support` module so third-party builds never see it (ltk's own `make test` enables it). ### Changed - **`OverlaySpec::size`** is now `( Length, Length )` (was `( u32, u32 )`), resolved against the main surface when the overlay is materialized; wrap existing sizes in `Length::px( … )` for the old fixed behaviour. - **`TextEdit::font_size`** and **`Separator::thickness` / `pad_v`** now take `impl Into` (were `f32`), resolved like the button label (font space) / geometry space; the `f32` sentinels are gone (`f32` call sites still compile via `Into`). - **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`). ## [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. ### Added - **`Canvas::set_clip_path`** — anti-aliased clipping to an arbitrary vector path (`&[PathCmd]`) on both backends. The software backend installs a tiny-skia coverage mask; the GLES backend captures the clipped draws into an offscreen layer and composites them back through an anti-aliased coverage mask. Complements the existing rect clip (`set_clip_rects`) for shaped clips such as a circular avatar, a rounded card or a `VectorDrawable` mask. See `examples/clip_path.rs`. - **`Canvas::fill_path` / `Canvas::stroke_path`** over a new `PathCmd` command list (`MoveTo` / `LineTo` / `QuadTo` / `CubicTo` / `Close`, in surface coordinates) — renders an arbitrary vector path, a `Path`, a `VectorDrawable` or a Lottie frame. The software backend rasterises directly with tiny-skia; the GLES backend rasterises into a tiny-skia pixmap and uploads it, so both backends share the same path rasteriser and stay at visual parity. - **`Canvas::read_rgba_pixels`** — reads any canvas into tightly packed straight-alpha RGBA8 (top-left row first), on both the GLES and software backends (the software path un-premultiplies its pixmap). **`Canvas::is_software`** lets a caller branch on the backend (e.g. honour a real path clip on software but only a bounding rect on GLES). - **`measure_text( text, size )`** (re-exported at the crate root) — measures one line with the default UI font and the system fallback chain, returning `(width, line_height)` in pixels without a live `Canvas`, for an embedder's measure pass that must match the renderer's metrics. Backed by a process-wide cached primary-font handle. - **`Stack::push_placed`** — appends a child at an exact rect, bypassing alignment and intrinsic sizing, so a view tree whose geometry is computed elsewhere can be projected onto a Stack in paint order. **`Stack::push_placed_clipped`** additionally clips the child's subtree to a rect (Android's `clipChildren`): overflowing content is not painted. - **`ExternalSource::Cpu`** and the **`External::cpu`** constructor — an immediate-mode CPU drawing closure invoked once per frame with the canvas and the widget's laid-out rect, working on both backends. Hosts a custom `View.onDraw` straight onto the ltk canvas without a GL texture round-trip, unlike the existing `Texture` source which only renders on GLES. - **`RichText`** widget — wrapped paragraph text carrying a `Msg` per clickable link range; the layout pass emits one hit rect per link line so taps land on the link rather than the whole paragraph. The ltk side of an Android `Spanned` carrying `URLSpan` / `ClickableSpan`. ### Fixed - GLES clip-layer composite no longer renders path-clipped content vertically flipped: the offscreen layer was sampled at the inverted screen Y. The software backend was unaffected. - Gesture: the horizontal pager is driven only once the swipe axis locks horizontal. Previously the pre-lock lateral drift of a vertical gesture could arm the consumer's pager without a matching release event, which could freeze the surface until an unrelated gesture reset it. - Software/GLES parity: the software backend now snaps glyph pen positions and image destinations to integer pixels (rounding to nearest), matching the GLES backend. Previously it truncated, so text and 1:1 images could land up to half a pixel off between backends and sample ~1 px softer. ### Changed - Default theme launcher SVGs replaced with renderer-compatible versions. ## [0.1.0] — 2026-03-10 - Initial release. [0.2.0]: https://github.com/liberux/ltk/releases/tag/v0.2.0 [0.1.0]: https://github.com/liberux/ltk/releases/tag/v0.1.0