text_edit font sizing on Length; add Button::width and Text::line_height
Some checks failed
CI / build + test (push) Has been cancelled
CI / cargo audit (push) Has been cancelled

Unify TextEdit's font size with the button label. The button resolved its `font_size` Length in font space (`viewport_logical`, so the `× dpi_scale` at raster lands the right physical size), while `TextEdit::font_size` took a raw `f32` that the draw / hit-test paths treated as a logical size. A caller that resolved a Length against the physical surface and passed the result as that `f32` therefore double-counted `dpi_scale` and got a font that rendered too large. `TextEdit::font_size` now takes `impl Into<Length>` and is resolved against `viewport_logical` exactly like the button, so the two paths agree. The field stores `Option<Length>` (`None` follows the widget-scaling mode at the theme default), retiring the old `f32` sentinel (`0.0` = mode, negative = fluid design px). `font_size_fluid` becomes shorthand for `Length::fluid( n )`. The `Option<Length>` flows through the `WidgetHandlers::TextEdit` snapshot and `text_input_geometry` and is resolved at draw / hit-test time, both of which carry a canvas; the inner measure helpers (`wrapping`, `hit_test`) keep `f32` because they receive the already-resolved value. Backward compatible: `f32` call sites still compile via `f32: Into<Length>` (→ `Length::px`), with the same result as before.
Add `Button::width( impl Into<Length> )`. Text buttons size to their label plus padding; some layouts need a pinned width instead — a full-width or surface-proportional button. The new builder mirrors `height`: resolved in physical layout space, clamped to the available `max_width`, propagated through `map_msg`, and a no-op for icon buttons.
Add `Text::line_height( mult )`. Wrapped multi-line text used the font's declared leading (`new_line_size`), which is tight for some labels; the multiplier scales the gap between wrapped lines (`1.0`, the default, keeps the natural leading — every other `text` is unchanged — and a `0.5` floor keeps lines from overlapping). Applied uniformly in `preferred_size` and `draw` so the reported height and the drawn baselines stay consistent.
Tests: `button` gains a pinned-width and a size-to-content case; `text` gains a line-height default / clamp test and a check that doubling the line height doubles a wrapped block's reported height. Docs: `docs/widgets.md` `text` / `button` / `separator` sections updated for the new builders, and a `CHANGELOG.md` "Unreleased" section covering this batch alongside the responsive work already landed.
This commit is contained in:
2026-07-10 10:38:30 +02:00
parent ce893ac776
commit 8762ab9ce0
11 changed files with 176 additions and 62 deletions

View File

@@ -37,15 +37,21 @@ patterns built from these widgets, see [`docs/cookbook.md`](./cookbook.md).
### `button`
A standard text button. Activates on tap, Enter, or Space when focused.
`font_size`, `height` and `width` all take an `impl Into<Length>`, so the
box can scale with the surface (e.g. a full-width form button) instead of
sizing to its label.
**When**: any place a normal app would have a "Save" / "Cancel" / "Send"
control.
```rust,no_run
# use ltk::{ button, Element };
# use ltk::{ button, Element, Length };
# #[ derive( Clone ) ] enum Msg { Save }
# fn _ex() -> Element<Msg> {
button( "Save" ).on_press( Msg::Save )
button( "Save" )
.height( Length::vmin( 9.0 ).clamp( 44.0, 72.0 ) )
.width( Length::orient( 95.0, 25.0 ) )
.on_press( Msg::Save )
.into()
# }
```
@@ -297,18 +303,24 @@ without a known fraction.
### `text`
A single-line label. Truncates with an ellipsis when wider than its
allocated rect.
A text label. By default it stays on one line and truncates with an
ellipsis when wider than its rect; `wrap( true )` instead word-wraps to
the layout width, and `line_height( mult )` scales the gap between the
wrapped lines (`1.0` = the font's natural leading).
**When**: titles, captions, anything non-interactive.
**When**: titles, captions, multi-line hints, anything non-interactive.
```rust,no_run
# use ltk::{ text, Color, Element };
# #[ derive( Clone ) ] enum Msg {}
# fn _ex() -> ( Element<Msg>, Element<Msg> ) {
# fn _ex() -> ( Element<Msg>, Element<Msg>, Element<Msg> ) {
let title = text( "Title" ).size( 24.0 ).color( Color::WHITE );
let centred = text( "Centred" ).align_center();
# ( title.into(), centred.into() )
let hint = text( "Swipe up or press Enter to unlock" )
.align_center()
.wrap( true )
.line_height( 1.4 );
# ( title.into(), centred.into(), hint.into() )
# }
```
@@ -424,7 +436,11 @@ card interactive.
### `separator`
A horizontal divider line with theme-default colour and 1 px thickness.
A horizontal divider line with a theme-default colour and a mode-scaled
thickness / vertical padding. `thickness` and `pad_v` take an `impl
Into<Length>`; both default to the process widget-scaling mode, and
passing `pad_v( 0.0 )` gives a flush, padding-less divider (distinct from
the mode default).
**When**: visual breaks between settings groups, list categories,
content blocks.