cranpose_ui/widgets/
button.rs1use std::{cell::RefCell, rc::Rc};
4
5use cranpose_core::NodeId;
6use cranpose_ui_layout::{HorizontalAlignment, LinearArrangement};
7
8use crate::{
9 composable, interaction::MutableInteractionSource, layout::policies::FlexMeasurePolicy,
10 modifier::Modifier, widgets::Layout,
11};
12
13#[derive(Clone, Debug, Default, PartialEq)]
15pub struct ButtonSpec {
16 pub interaction_source: Option<MutableInteractionSource>,
19}
20
21impl ButtonSpec {
22 pub fn new() -> Self {
24 Self::default()
25 }
26
27 pub fn interaction_source(mut self, interaction_source: MutableInteractionSource) -> Self {
29 self.interaction_source = Some(interaction_source);
30 self
31 }
32}
33
34fn button_modifier<F>(modifier: Modifier, spec: ButtonSpec, on_click: F) -> Modifier
35where
36 F: FnMut() + 'static,
37{
38 let on_click_rc: Rc<RefCell<dyn FnMut()>> = Rc::new(RefCell::new(on_click));
39 let modifier = if let Some(interaction_source) = spec.interaction_source {
40 modifier.press_interaction_source(interaction_source)
41 } else {
42 modifier
43 };
44
45 modifier.clickable(move |_point| {
46 (on_click_rc.borrow_mut())();
47 })
48}
49
50#[composable]
71pub fn Button<F, G>(modifier: Modifier, spec: ButtonSpec, on_click: F, content: G) -> NodeId
72where
73 F: FnMut() + 'static,
74 G: FnMut() + 'static,
75{
76 Layout(
77 button_modifier(modifier, spec, on_click),
78 FlexMeasurePolicy::column(
79 LinearArrangement::Center,
80 HorizontalAlignment::CenterHorizontally,
81 crate::density::density().density(),
82 ),
83 content,
84 )
85}
86
87#[cfg(test)]
88#[path = "tests/button_tests.rs"]
89mod tests;