graphix_package_gui/widgets/
context_menu.rs1use super::context_menu_widget::OwnedContextMenu;
2use super::menu_bar::{compile_menu_items, menu_item_desc, MenuItemKind};
3use super::{compile, GuiW, GuiWidget, IcedElement};
4use anyhow::{Context, Result};
5use arcstr::ArcStr;
6use graphix_compiler::expr::ExprId;
7use graphix_rt::{CallableId, GXExt, GXHandle, Ref};
8use netidx::publisher::Value;
9use tokio::try_join;
10
11pub(crate) struct ContextMenuW<X: GXExt> {
12 gx: GXHandle<X>,
13 child_ref: Ref<X>,
14 child: GuiW<X>,
15 items_ref: Ref<X>,
16 items: Vec<MenuItemKind<X>>,
17}
18
19impl<X: GXExt> ContextMenuW<X> {
20 pub(crate) async fn compile(gx: GXHandle<X>, source: Value) -> Result<GuiW<X>> {
21 let [(_, child), (_, items)] =
22 source.cast_to::<[(ArcStr, u64); 2]>().context("context_menu flds")?;
23 let (child_ref, items_ref) = try_join! {
24 gx.compile_ref(child),
25 gx.compile_ref(items),
26 }?;
27 let compiled_child = compile_child!(gx, child_ref, "context_menu child");
28 let compiled_items = match items_ref.last.as_ref() {
29 Some(v) => {
30 compile_menu_items(&gx, v.clone()).await.context("context_menu items")?
31 }
32 None => vec![],
33 };
34 Ok(Box::new(Self {
35 gx: gx.clone(),
36 child_ref,
37 child: compiled_child,
38 items_ref,
39 items: compiled_items,
40 }))
41 }
42}
43
44impl<X: GXExt> GuiWidget<X> for ContextMenuW<X> {
45 fn handle_update(
46 &mut self,
47 rt: &tokio::runtime::Handle,
48 id: ExprId,
49 v: &Value,
50 ) -> Result<bool> {
51 let mut changed = false;
52 update_child!(
53 self, rt, id, v, changed, child_ref, child,
54 "context_menu child recompile"
55 );
56 if id == self.items_ref.id {
57 self.items_ref.last = Some(v.clone());
58 self.items = rt
59 .block_on(compile_menu_items(&self.gx, v.clone()))
60 .context("context_menu items recompile")?;
61 changed = true;
62 }
63 for item in &mut self.items {
64 match item {
65 MenuItemKind::Action {
66 label,
67 shortcut,
68 on_click,
69 on_click_callable,
70 disabled,
71 } => {
72 changed |= label
73 .update(id, v)
74 .context("context_menu item update label")?
75 .is_some();
76 changed |= shortcut
77 .update(id, v)
78 .context("context_menu item update shortcut")?
79 .is_some();
80 changed |= disabled
81 .update(id, v)
82 .context("context_menu item update disabled")?
83 .is_some();
84 if id == on_click.id {
85 on_click.last = Some(v.clone());
86 *on_click_callable = Some(
87 rt.block_on(self.gx.compile_callable(v.clone()))
88 .context("context_menu item on_click recompile")?,
89 );
90 }
91 }
92 MenuItemKind::Divider => {}
93 }
94 }
95 Ok(changed)
96 }
97
98 fn editor_action(
99 &mut self,
100 id: ExprId,
101 action: &iced_widget::text_editor::Action,
102 ) -> Option<(CallableId, Value)> {
103 self.child.editor_action(id, action)
104 }
105
106 fn view(&self) -> IcedElement<'_> {
107 let items = self.items.iter().map(menu_item_desc).collect();
108 OwnedContextMenu::new(self.child.view(), items).into()
109 }
110}