//! `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, grid, progress_bar, 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<Message>
	{
		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.
		// Mode + density controls. Stock buttons like the demo widgets
		// below, so they follow the active mode too. The switch gets the
		// full width and the density pair half a cell each: every button
		// clamps to its slot instead of overflowing a shared row, and the
		// slots leave room for Physical-mode text at raised densities.
		let controls = column::<Message>()
			.padding( 0.0 )
			.spacing( 8.0 )
			.push( button::<Message>( "Switch mode".to_string() )
				.variant( ButtonVariant::Primary )
				.on_press( Message::SwitchMode ) )
			.push( grid::<Message>( 2 )
				.push( button::<Message>( "− density".to_string() )
					.on_press( Message::DensityDown ) )
				.push( button::<Message>( "＋ density".to_string() )
					.on_press( Message::DensityUp ) ) );

		// The demo widgets — NO explicit sizes, so they follow the mode.
		let demo = column::<Message>()
			.spacing( 16.0 )
			.max_width( 520.0 )
			.push( button::<Message>( "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::<Message>()
			.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<Message>
	{
		if keysym == Keysym::Escape
		{
			std::process::exit( 0 );
		}
		None
	}
}

fn main()
{
	ltk::run( ResponsiveApp::new() );
}
