ltk/widget/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Widgets — the interactive and decorative leaves of the [`Element`] tree.
//!
//! Each widget lives in its own submodule and is reached through the
//! crate-root re-exports (`button`, `text`, `text_edit`, `slider`, …) plus
//! the `img_widget` alias for [`image::Image`]. Construct one from its
//! free constructor function, configure it through builder-style methods,
//! and convert it into [`Element<Msg>`] via `.into()` when pushing it
//! into a layout.
//!
//! ```rust,no_run
//! # use ltk::{ button, column, slider, text, Element };
//! # #[ derive( Clone ) ] enum Msg { SetVolume( f32 ), Mute }
//! # struct App { volume: f32 }
//! # impl App { fn _ex( &self ) -> Element<Msg> {
//! column()
//! .push( text( "Volume" ) )
//! .push( slider( self.volume ).on_change( |v| Msg::SetVolume( v ) ) )
//! .push( button( "Mute" ).on_press( Msg::Mute ) )
//! .into()
//! # }}
//! ```
//!
//! ## What lives here
//!
//! * **Buttons / activations**: [`button::Button`],
//! [`pressable::Pressable`], [`window_button::WindowButton`],
//! [`list_item::ListItem`].
//! * **Stateful binary controls**: [`toggle::Toggle`],
//! [`checkbox::Checkbox`], [`radio::Radio`].
//! * **Continuous controls**: [`slider::Slider`], [`vslider::VSlider`],
//! [`progress_bar::ProgressBar`].
//! * **Text**: [`text::Text`], [`text_edit::TextEdit`].
//! * **Images / decoration**: [`image::Image`], [`separator::Separator`],
//! [`container::Container`].
//! * **Clipping wrappers**: [`scroll::Scroll`] (with gesture-driven
//! scrolling), [`viewport::Viewport`] (passive clip / fade),
//! [`flex::Flex`] (treats a non-spacer child as a row filler), and
//! [`carousel::Carousel`] (horizontal focused-tile carousel with
//! host-controlled offset).
//! * **Overlays**: [`dialog::Dialog`] (modal / non-modal centered
//! confirmation card with built-in scrim, ESC-to-cancel, and
//! tap-outside-to-dismiss for the non-modal variant).
//!
//! Layouts ([`column`](crate::column), [`row`](crate::row),
//! [`stack`](crate::stack), [`grid`](crate::grid),
//! [`spacer`](crate::spacer)) live in [`crate::layout`]; they share the
//! same [`Element`] tree but are kept separate to make the "what does
//! this paint" / "how is this arranged" distinction explicit.
//!
//! ## Per-leaf handler snapshot
//!
//! [`WidgetHandlers`] is the snapshot the layout pass takes of every
//! interactive widget so the input handlers can dispatch in O(1) without
//! re-walking the [`Element`] tree. It is `pub( crate )` plumbing for the
//! runtime; downstream apps usually never see it. The `test_support`
//! module re-exports it for integration tests that want to assert on the
//! handler shape.
pub mod button;
pub mod container;
pub mod text_edit;
pub mod image;
pub mod text;
pub mod scroll;
pub mod viewport;
pub mod slider;
pub mod vslider;
pub mod toggle;
pub mod separator;
pub mod progress_bar;
pub mod checkbox;
pub mod radio;
pub mod list_item;
pub mod window_button;
pub mod pressable;
pub mod flex;
pub mod combo;
pub mod anchored_overlay;
pub mod spinner;
pub mod tab_bar;
pub mod toast;
pub mod tooltip;
pub mod notebook;
pub mod date_picker;
pub mod time_picker;
pub mod color_picker;
pub mod dialog;
pub mod external;
pub mod carousel;
pub mod element;
pub mod handlers;
pub mod laid_out;
pub mod factory;
pub use element::Element;
pub use handlers::WidgetHandlers;
pub use laid_out::LaidOutWidget;
pub use factory::{ button, icon_button, text_edit, image, text, container, external };
/// Type alias for the message-mapping closure shared across an
/// [`Element::map`] walk. Stored as `Arc<dyn Fn>` so every per-widget
/// `map_msg` can clone and re-share it without copying the closure body
/// — the same closure is invoked once per emitted message, regardless
/// of how many leaves the sub-tree has.
pub( crate ) type MapFn<Msg, U> = std::sync::Arc<dyn Fn( Msg ) -> U>;