Skip to main content

graphix_package_gui/widgets/
button.rs

1use super::{compile, GuiW, GuiWidget, IcedElement, Message};
2use crate::types::{LengthV, PaddingV};
3use anyhow::{Context, Result};
4use arcstr::ArcStr;
5use graphix_compiler::expr::ExprId;
6use graphix_rt::{Callable, CallableId, GXExt, GXHandle, Ref, TRef};
7use iced_widget as widget;
8use netidx::{protocol::valarray::ValArray, publisher::Value};
9use tokio::try_join;
10
11pub(crate) struct ButtonW<X: GXExt> {
12    gx: GXHandle<X>,
13    disabled: TRef<X, bool>,
14    width: TRef<X, LengthV>,
15    height: TRef<X, LengthV>,
16    padding: TRef<X, PaddingV>,
17    on_press: Ref<X>,
18    on_press_callable: Option<Callable<X>>,
19    child_ref: Ref<X>,
20    child: GuiW<X>,
21}
22
23impl<X: GXExt> ButtonW<X> {
24    pub(crate) async fn compile(gx: GXHandle<X>, source: Value) -> Result<GuiW<X>> {
25        let [(_, child), (_, disabled), (_, height), (_, on_press), (_, padding), (_, width)] =
26            source.cast_to::<[(ArcStr, u64); 6]>().context("button flds")?;
27        let (child_ref, disabled, height, on_press, padding, width) = try_join! {
28            gx.compile_ref(child),
29            gx.compile_ref(disabled),
30            gx.compile_ref(height),
31            gx.compile_ref(on_press),
32            gx.compile_ref(padding),
33            gx.compile_ref(width),
34        }?;
35        let compiled_child = compile_child!(gx, child_ref, "button child");
36        let callable = compile_callable!(gx, on_press, "button on_press");
37        Ok(Box::new(Self {
38            gx: gx.clone(),
39            disabled: TRef::new(disabled).context("button tref disabled")?,
40            width: TRef::new(width).context("button tref width")?,
41            height: TRef::new(height).context("button tref height")?,
42            padding: TRef::new(padding).context("button tref padding")?,
43            on_press,
44            on_press_callable: callable,
45            child_ref,
46            child: compiled_child,
47        }))
48    }
49}
50
51impl<X: GXExt> GuiWidget<X> for ButtonW<X> {
52    fn handle_update(
53        &mut self,
54        rt: &tokio::runtime::Handle,
55        id: ExprId,
56        v: &Value,
57    ) -> Result<bool> {
58        let mut changed = false;
59        changed |=
60            self.disabled.update(id, v).context("button update disabled")?.is_some();
61        changed |= self.width.update(id, v).context("button update width")?.is_some();
62        changed |= self.height.update(id, v).context("button update height")?.is_some();
63        changed |= self.padding.update(id, v).context("button update padding")?.is_some();
64        update_callable!(self, rt, id, v, on_press, on_press_callable, "button on_press recompile");
65        update_child!(self, rt, id, v, changed, child_ref, child, "button child recompile");
66        Ok(changed)
67    }
68
69    fn editor_action(
70        &mut self,
71        id: ExprId,
72        action: &iced_widget::text_editor::Action,
73    ) -> Option<(CallableId, Value)> {
74        self.child.editor_action(id, action)
75    }
76
77    fn view(&self) -> IcedElement<'_> {
78        let mut btn = widget::Button::new(self.child.view());
79        if !self.disabled.t.unwrap_or(false) {
80            if let Some(callable) = &self.on_press_callable {
81                btn = btn.on_press(Message::Call(
82                    callable.id(),
83                    ValArray::from_iter([Value::Null]),
84                ));
85            }
86        }
87        if let Some(w) = self.width.t.as_ref() {
88            btn = btn.width(w.0);
89        }
90        if let Some(h) = self.height.t.as_ref() {
91            btn = btn.height(h.0);
92        }
93        if let Some(p) = self.padding.t.as_ref() {
94            btn = btn.padding(p.0);
95        }
96        btn.into()
97    }
98}