//! `cargo run --example responsive` //! //! Demonstrates ltk's two responsive modes side by side on stock widgets. //! None of the widgets below set an explicit size — they all follow the //! process-wide [`ltk::WidgetScaling`] mode: //! //! - **Fluid** (the default): sizes are a fraction of the surface, so the //! whole set grows and shrinks as you resize the window. //! - **Physical**: sizes are a constant real-world size scaled by //! [`ltk::density`], independent of the surface. //! //! Tap **Switch mode** to flip between them, and **−/+ density** to change //! the physical density. Watch the button, field, checkbox, switch, slider //! and progress bar resize (or not) accordingly. Esc exits. //! //! NOTE: ltk is a Wayland layer-shell toolkit. This example requires a running //! Wayland compositor (e.g. sway, labwc, or a full desktop session). use ltk:: { App, Element, Keysym, ButtonVariant, WidgetScaling, button, checkbox, column, progress_bar, row, separator, slider, spacer, text, text_edit, toggle, set_widget_scaling, set_density, density, }; #[ derive( Clone ) ] enum Message { SwitchMode, DensityUp, DensityDown, NameChanged( String ), ToggleCheck, ToggleSwitch, SliderChanged( f32 ), } struct ResponsiveApp { physical: bool, name: String, checked: bool, switched: bool, volume: f32, } impl ResponsiveApp { fn new() -> Self { // Start in the default fluid mode with a neutral density. set_widget_scaling( WidgetScaling::Fluid ); set_density( 1.5 ); Self { physical: false, name: String::new(), checked: true, switched: false, volume: 0.4, } } } impl App for ResponsiveApp { type Message = Message; fn view( &self ) -> Element { let palette = ltk::theme_palette(); let primary = palette.text_primary; let secondary = palette.text_secondary; let mode_label = if self.physical { format!( "Mode: Physical (density {:.1})", density() ) } else { "Mode: Fluid (resize the window to see it scale)".to_string() }; // Mode + density controls. Explicit sizes here so the controls stay // stable while the demo widgets below react to the mode. let controls = row::() .spacing( 12.0 ) .push( button::( "Switch mode".to_string() ) .variant( ButtonVariant::Primary ) .font_size( 16.0 ) .height( 44.0 ) .on_press( Message::SwitchMode ) ) .push( button::( "− density".to_string() ) .font_size( 16.0 ) .height( 44.0 ) .on_press( Message::DensityDown ) ) .push( button::( "+ density".to_string() ) .font_size( 16.0 ) .height( 44.0 ) .on_press( Message::DensityUp ) ); // The demo widgets — NO explicit sizes, so they follow the mode. let demo = column::() .spacing( 16.0 ) .max_width( 520.0 ) .push( button::( "A stock button".to_string() ).variant( ButtonVariant::Secondary ).on_press( Message::SwitchMode ) ) .push( text_edit( "A stock text field".to_string(), self.name.clone() ).on_change( Message::NameChanged ) ) .push( checkbox( self.checked ).label( "A stock checkbox".to_string() ).on_toggle( Message::ToggleCheck ) ) .push( toggle( self.switched ).label( "A stock switch".to_string() ).on_toggle( Message::ToggleSwitch ) ) .push( slider( self.volume ).on_change( Message::SliderChanged ) ) .push( progress_bar( self.volume ) ); column::() .padding( 32.0 ) .spacing( 20.0 ) .center_y( true ) .push( text( "ltk responsive modes".to_string() ).size( 26.0 ).color( primary ).align_center() ) .push( text( mode_label ).size( 15.0 ).color( secondary ).align_center() ) .push( controls ) .push( separator() ) .push( demo ) .push( spacer().weight( 1 ) ) .push( text( "Esc to exit".to_string() ).size( 12.0 ).color( secondary ).align_center() ) .into() } fn update( &mut self, msg: Message ) { match msg { Message::SwitchMode => { self.physical = !self.physical; set_widget_scaling( if self.physical { WidgetScaling::Physical } else { WidgetScaling::Fluid } ); } Message::DensityUp => set_density( ( density() + 0.25 ).min( 4.0 ) ), Message::DensityDown => set_density( ( density() - 0.25 ).max( 0.5 ) ), Message::NameChanged( v ) => self.name = v, Message::ToggleCheck => self.checked = !self.checked, Message::ToggleSwitch => self.switched = !self.switched, Message::SliderChanged( v ) => self.volume = v, } } fn on_key( &mut self, keysym: Keysym ) -> Option { if keysym == Keysym::Escape { std::process::exit( 0 ); } None } } fn main() { ltk::run( ResponsiveApp::new() ); }