container, text, date_picker: width-aware sizing pass

`Container::max_width(px)` mirrors the same flag on `Column` / `Row` — the container reports `min( offered, px )` upwards and the draw pass caps `rect.width` to `px`, so a decorated child wrapped in `container().max_width(260)` no longer needs a `column()`-of-one shell just to access the cap. Propagated through `map_msg`, covered by a test, and documented under the `container` section of `docs/widgets.md`.
`Text::no_truncate()` opts out of the default ellipsis behaviour: when `truncate = false` the draw pass paints the full string even if `measure(text) > rect.width`. Useful for very short labels (calendar days "1"–"31", day-of-week stubs "Lu" / "Mi" / "Sá") inside grid slots whose width is dictated by the parent — a couple of pixels of overflow centred in the rect is invisible, while "..." in place of a single-digit number is loud.
`DatePicker::width(px)` is a layout hint: when set, `build()` derives `header_fs`, `dow_fs` and `day_fs` from the slot width so the worst-case label in each row ("September 2026" in the header, "Mié" / "Sáb" in the DOW row, "30" in the day cell) fits at a sensible size; the design defaults stay as upper bounds. Day and DOW cells also flip on `Text::no_truncate()` as a safety net — heuristic font sizing can't perfectly predict glyph widths across families, and overflowing one pixel beats truncating to "...".
This commit is contained in:
2026-05-13 19:38:41 +02:00
parent 96f437544a
commit 821037f509
6 changed files with 102 additions and 19 deletions

View File

@@ -213,6 +213,7 @@ pub struct DatePicker<Msg: Clone>
pub on_change: Option<Arc<dyn Fn( Date ) -> Msg>>,
pub on_navigate: Option<Arc<dyn Fn( i32, u8 ) -> Msg>>,
pub locale: Locale,
pub width: Option<f32>,
}
impl<Msg: Clone + 'static> DatePicker<Msg>
@@ -231,6 +232,7 @@ impl<Msg: Clone + 'static> DatePicker<Msg>
on_change: None,
on_navigate: None,
locale: Locale::default(),
width: None,
}
}
@@ -274,6 +276,17 @@ impl<Msg: Clone + 'static> DatePicker<Msg>
self
}
/// Outer width the picker will be laid out at. Used to shrink the
/// header / day-of-week / day-cell font sizes so the widest labels
/// ("30", "September 2026", "Mié") still fit without ellipsis. When
/// unset, the picker uses the design defaults and may truncate
/// inside very narrow rects.
pub fn width( mut self, w: f32 ) -> Self
{
self.width = Some( w );
self
}
/// Build the `Element` tree representing this date picker.
pub fn build( self ) -> Element<Msg>
{
@@ -290,6 +303,18 @@ impl<Msg: Clone + 'static> DatePicker<Msg>
let on_nav = self.on_navigate.clone();
let first = self.locale.first_dow;
let ( header_fs, dow_fs, day_fs ) = if let Some( w ) = self.width
{
let inner_w = ( w - 2.0 * theme::PADDING ).max( 8.0 );
let slot_w = ( ( inner_w - 6.0 * theme::SPACING ) / 7.0 ).max( 4.0 );
let day = ( ( slot_w - 8.0 ) / 1.6 ).clamp( 8.0, theme::DAY_FS );
let dow = ( slot_w / 2.0 ).clamp( 8.0, theme::DOW_FS );
let head = ( ( inner_w - 52.0 ) / ( 14.0 * 0.7 ) ).clamp( 10.0, theme::HEADER_FS );
( head, dow, day )
} else {
( theme::HEADER_FS, theme::DOW_FS, theme::DAY_FS )
};
// Header chevrons load from the active theme as SVG icons
// (`icons/catalogue/filled/multimedia/{previous,next}.svg`),
// tinted to the primary text colour so they read against
@@ -333,11 +358,11 @@ impl<Msg: Clone + 'static> DatePicker<Msg>
// `Stack` (the only layout that lets independent children
// sit at left / centre / right of the same rect) wrapped in a
// container that fixes the row height.
let header_height = ( CHEVRON_PX as f32 + 16.0 ).max( theme::HEADER_FS + 16.0 );
let header_height = ( CHEVRON_PX as f32 + 16.0 ).max( header_fs + 16.0 );
let header_inner: Element<Msg> = stack::<Msg>()
.push_aligned( prev, HAlign::Start, VAlign::Center )
.push_aligned(
text( title ).size( theme::HEADER_FS ).color( theme::text() ),
text( title ).size( header_fs ).color( theme::text() ),
HAlign::Center, VAlign::Center,
)
.push_aligned( next, HAlign::End, VAlign::Center )
@@ -360,9 +385,10 @@ impl<Msg: Clone + 'static> DatePicker<Msg>
let dow = ( ( slot + first ) % 7 ) as u8;
let cell: Element<Msg> = container::<Msg>(
text( dow_short( dow ) )
.size( theme::DOW_FS )
.size( dow_fs )
.color( theme::text_muted() )
.align_center(),
.align_center()
.no_truncate(),
)
.padding_h( 0.0 )
.padding_v( 4.0 )
@@ -404,9 +430,10 @@ impl<Msg: Clone + 'static> DatePicker<Msg>
let mut card = container::<Msg>(
text( format!( "{}", day ) )
.size( theme::DAY_FS )
.size( day_fs )
.color( label_color )
.align_center(),
.align_center()
.no_truncate(),
)
.padding_h( 4.0 )
.padding_v( 8.0 )