graphix_package_gui/widgets/
button.rs1use 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}