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)]
14pub struct ButtonSpec {
15 pub interaction_source: Option<MutableInteractionSource>,
16}
17
18impl ButtonSpec {
19 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn interaction_source(mut self, interaction_source: MutableInteractionSource) -> Self {
24 self.interaction_source = Some(interaction_source);
25 self
26 }
27}
28
29fn button_modifier<F>(modifier: Modifier, spec: ButtonSpec, on_click: F) -> Modifier
30where
31 F: FnMut() + 'static,
32{
33 let on_click_rc: Rc<RefCell<dyn FnMut()>> = Rc::new(RefCell::new(on_click));
34 let modifier = if let Some(interaction_source) = spec.interaction_source {
35 modifier.press_interaction_source(interaction_source)
36 } else {
37 modifier
38 };
39
40 modifier.clickable(move |_point| {
41 (on_click_rc.borrow_mut())();
42 })
43}
44
45#[composable]
69pub fn Button<F, G>(modifier: Modifier, spec: ButtonSpec, on_click: F, content: G) -> NodeId
70where
71 F: FnMut() + 'static,
72 G: FnMut() + 'static,
73{
74 Layout(
75 button_modifier(modifier, spec, on_click),
76 FlexMeasurePolicy::column(
77 LinearArrangement::Center,
78 HorizontalAlignment::CenterHorizontally,
79 ),
80 content,
81 )
82}
83
84#[cfg(test)]
85#[path = "tests/button_tests.rs"]
86mod tests;