cranpose_ui/widgets/button.rs
1//! Button widget implementation
2
3#![allow(non_snake_case)]
4
5use crate::composable;
6use crate::layout::policies::FlexMeasurePolicy;
7use crate::modifier::Modifier;
8use crate::widgets::Layout;
9use cranpose_core::NodeId;
10use cranpose_ui_layout::{HorizontalAlignment, LinearArrangement};
11
12/// A clickable button with a background and content.
13///
14/// # When to use
15/// Use this to trigger an action when clicked. The button serves as a container
16/// for other composables (typically `Text`).
17///
18/// # Arguments
19///
20/// * `modifier` - Modifiers to apply to the button container (e.g., size, padding).
21/// * `on_click` - The callback to execute when the button is clicked.
22/// * `content` - The content to display inside the button (e.g., `Text` or `Icon`).
23///
24/// # Example
25///
26/// ```rust,ignore
27/// Button(
28/// Modifier::padding(8.0),
29/// || println!("Clicked!"),
30/// || Text("Click Me", Modifier::empty())
31/// );
32/// ```
33#[composable]
34pub fn Button<F, G>(modifier: Modifier, on_click: F, content: G) -> NodeId
35where
36 F: FnMut() + 'static,
37 G: FnMut() + 'static,
38{
39 use std::cell::RefCell;
40 use std::rc::Rc;
41
42 // Wrap the on_click handler in Rc<RefCell<>> to make it callable from Fn closure
43 let on_click_rc: Rc<RefCell<dyn FnMut()>> = Rc::new(RefCell::new(on_click));
44
45 // Add clickable modifier to handle click events
46 let clickable_modifier = modifier.clickable(move |_point| {
47 (on_click_rc.borrow_mut())();
48 });
49
50 // Use Layout with FlexMeasurePolicy (column) to arrange button content
51 // This matches how Button is implemented in Jetpack Compose
52 Layout(
53 clickable_modifier,
54 FlexMeasurePolicy::column(
55 LinearArrangement::Center,
56 HorizontalAlignment::CenterHorizontally,
57 ),
58 content,
59 )
60}