Support viewport-relative widget sizing
Some checks failed
CI / build + test (push) Has been cancelled
CI / cargo audit (push) Has been cancelled

This commit is contained in:
yamabush1
2026-06-04 12:38:59 +02:00
parent ae8380b1ac
commit 68c6a87bf6
8 changed files with 61 additions and 33 deletions

View File

@@ -2,7 +2,7 @@
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
use std::sync::Arc;
use crate::types::Rect;
use crate::types::{ Length, Rect };
use crate::render::Canvas;
use super::Element;
use super::slider::intersect_clip;
@@ -65,10 +65,10 @@ pub struct VSlider<Msg: Clone>
/// Current value in `[0.0, 1.0]`. `0.0` paints no fill; `1.0` fills the
/// whole pill.
pub value: f32,
/// Fixed width of the pill in pixels. Defaults to 56.
pub width: f32,
/// Fixed height of the pill in pixels. Defaults to 160.
pub height: f32,
/// Fixed width of the pill in logical units. Defaults to 56 px.
pub width: Length,
/// Fixed height of the pill in logical units. Defaults to 160 px.
pub height: Length,
/// Callback invoked with the new value when the slider is tapped or
/// dragged. `Arc` (not `Box`) so the layout pass can clone it into the
/// per-leaf handler snapshot for O(1) dispatch on input events.
@@ -93,8 +93,8 @@ impl<Msg: Clone> VSlider<Msg>
Self
{
value: value.clamp( 0.0, 1.0 ),
width: theme::WIDTH,
height: theme::HEIGHT,
width: Length::px( theme::WIDTH ),
height: Length::px( theme::HEIGHT ),
on_change: None,
track_surface: theme::SURFACE_TRACK,
fill_surface: theme::SURFACE_FILL,
@@ -117,12 +117,13 @@ impl<Msg: Clone> VSlider<Msg>
self
}
/// Override the fixed pill `(width, height)` in pixels. Both are clamped
/// to a minimum of `2.0` so a rounded pill can always be drawn.
pub fn size( mut self, width: f32, height: f32 ) -> Self
/// Override the fixed pill `(width, height)` in logical units. Both are
/// clamped to a minimum of `2.0` after viewport-relative values resolve,
/// so a rounded pill can always be drawn.
pub fn size( mut self, width: impl Into<Length>, height: impl Into<Length> ) -> Self
{
self.width = width.max( 2.0 );
self.height = height.max( 2.0 );
self.width = width.into();
self.height = height.into();
self
}
@@ -135,9 +136,13 @@ impl<Msg: Clone> VSlider<Msg>
/// Return the preferred `(width, height)`. `max_width` is ignored — see
/// the type-level docs on intrinsic sizing.
pub fn preferred_size( &self, _max_width: f32, _canvas: &Canvas ) -> (f32, f32)
pub fn preferred_size( &self, _max_width: f32, canvas: &Canvas ) -> (f32, f32)
{
( self.width, self.height )
let viewport = canvas.viewport_logical();
(
self.width.resolve( viewport, Length::EM_BASE_DEFAULT ).max( 2.0 ),
self.height.resolve( viewport, Length::EM_BASE_DEFAULT ).max( 2.0 ),
)
}
/// Compute the value `[0.0, 1.0]` from a tap/drag y position within `rect`.

View File

@@ -100,8 +100,8 @@ fn preferred_size_ignores_max_width()
fn default_dimensions_are_the_theme_constants()
{
let s: VSlider<()> = vslider( 0.0 );
assert_eq!( s.width, theme::WIDTH );
assert_eq!( s.height, theme::HEIGHT );
assert_eq!( s.width, Length::px( theme::WIDTH ) );
assert_eq!( s.height, Length::px( theme::HEIGHT ) );
}
#[ test ]