ltk/widget/carousel/
mod.rsuse crate::render::Canvas;
use crate::types::{ Rect, WidgetId };
use crate::widget::Element;
#[ cfg( test ) ]
mod tests;
pub struct Carousel<Msg: Clone>
{
pub( crate ) children: Vec<Element<Msg>>,
pub( crate ) id: Option<WidgetId>,
pub( crate ) focused_width_frac: f32,
pub( crate ) gap: f32,
pub( crate ) offset: f32,
}
impl<Msg: Clone> Carousel<Msg>
{
pub fn push( mut self, child: impl Into<Element<Msg>> ) -> Self
{
self.children.push( child.into() );
self
}
pub fn id( mut self, id: WidgetId ) -> Self
{
self.id = Some( id );
self
}
pub fn focused_width_frac( mut self, f: f32 ) -> Self
{
self.focused_width_frac = f.clamp( 0.05, 1.0 );
self
}
pub fn gap( mut self, g: f32 ) -> Self
{
self.gap = g.max( 0.0 );
self
}
pub fn offset( mut self, o: f32 ) -> Self
{
self.offset = o;
self
}
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> ( f32, f32 )
{
if self.children.is_empty() { return ( max_width, 0.0 ); }
let child_w = ( max_width * self.focused_width_frac ).max( 1.0 );
let max_h = self.children.iter()
.map( |c| c.preferred_size( child_w, canvas ).1 )
.fold( 0.0_f32, f32::max );
( max_width, max_h )
}
pub fn snap_offset( &self, viewport_w: f32, idx: usize ) -> f32
{
if self.children.is_empty() { return 0.0; }
let child_w = ( viewport_w * self.focused_width_frac ).max( 1.0 );
let stride = child_w + self.gap;
-( idx as f32 ) * stride
}
pub fn focused_index( &self, viewport_w: f32 ) -> usize
{
if self.children.is_empty() { return 0; }
let child_w = ( viewport_w * self.focused_width_frac ).max( 1.0 );
let stride = child_w + self.gap;
let raw = -self.offset / stride;
raw.round().clamp( 0.0, ( self.children.len() - 1 ) as f32 ) as usize
}
pub fn layout( &self, rect: Rect, _canvas: &Canvas ) -> Vec<( Rect, usize )>
{
if self.children.is_empty() { return Vec::new(); }
let child_w = ( rect.width * self.focused_width_frac ).max( 1.0 );
let base_x = rect.x + ( rect.width - child_w ) / 2.0 + self.offset;
let stride = child_w + self.gap;
self.children.iter().enumerate().map( |( i, _ )|
{
let x = base_x + ( i as f32 ) * stride;
( Rect { x, y: rect.y, width: child_w, height: rect.height }, i )
}).collect()
}
pub fn draw( &self ) {}
pub( crate ) fn map_msg<U>( self, f: &super::MapFn<Msg, U> ) -> Carousel<U>
where
U: Clone + 'static,
Msg: 'static,
{
Carousel
{
children: self.children.into_iter().map( |c| c.map_arc( f ) ).collect(),
id: self.id,
focused_width_frac: self.focused_width_frac,
gap: self.gap,
offset: self.offset,
}
}
}
impl<Msg: Clone + 'static> From<Carousel<Msg>> for Element<Msg>
{
fn from( c: Carousel<Msg> ) -> Self
{
Element::Carousel( c )
}
}
pub fn carousel<Msg: Clone>() -> Carousel<Msg>
{
Carousel
{
children: Vec::new(),
id: None,
focused_width_frac: 0.8,
gap: 16.0,
offset: 0.0,
}
}