graphix-package-gui 0.8.0

A dataflow language for UIs and network programming, GUI package
Documentation
use super::{compile, GuiW, GuiWidget, IcedElement};
use crate::types::TooltipPositionV;
use anyhow::{Context, Result};
use arcstr::ArcStr;
use graphix_compiler::expr::ExprId;
use graphix_rt::{GXExt, GXHandle, Ref, TRef};
use iced_widget as widget;
use netidx::publisher::Value;
use tokio::try_join;

pub(crate) struct TooltipW<X: GXExt> {
    gx: GXHandle<X>,
    child_ref: Ref<X>,
    child: GuiW<X>,
    tip_ref: Ref<X>,
    tip: GuiW<X>,
    position: TRef<X, TooltipPositionV>,
    gap: TRef<X, Option<f64>>,
}

impl<X: GXExt> TooltipW<X> {
    pub(crate) async fn compile(gx: GXHandle<X>, source: Value) -> Result<GuiW<X>> {
        let [(_, child), (_, gap), (_, position), (_, tip)] =
            source.cast_to::<[(ArcStr, u64); 4]>().context("tooltip flds")?;
        let (child_ref, gap, position, tip_ref) = try_join! {
            gx.compile_ref(child),
            gx.compile_ref(gap),
            gx.compile_ref(position),
            gx.compile_ref(tip),
        }?;
        let compiled_child = compile_child!(gx, child_ref, "tooltip child");
        let compiled_tip = compile_child!(gx, tip_ref, "tooltip tip");
        Ok(Box::new(Self {
            gx: gx.clone(),
            child_ref,
            child: compiled_child,
            tip_ref,
            tip: compiled_tip,
            position: TRef::new(position).context("tooltip tref position")?,
            gap: TRef::new(gap).context("tooltip tref gap")?,
        }))
    }
}

impl<X: GXExt> GuiWidget<X> for TooltipW<X> {
    fn children_mut(&mut self) -> &mut [GuiW<X>] {
        std::slice::from_mut(&mut self.child)
    }

    fn children(&self) -> &[GuiW<X>] {
        std::slice::from_ref(&self.child)
    }

    fn handle_update(
        &mut self,
        rt: &tokio::runtime::Handle,
        id: ExprId,
        v: &Value,
    ) -> Result<bool> {
        let mut changed = false;
        changed |=
            self.position.update(id, v).context("tooltip update position")?.is_some();
        changed |= self.gap.update(id, v).context("tooltip update gap")?.is_some();
        update_child!(
            self,
            rt,
            id,
            v,
            changed,
            child_ref,
            child,
            "tooltip child recompile"
        );
        update_child!(self, rt, id, v, changed, tip_ref, tip, "tooltip tip recompile");
        Ok(changed)
    }

    fn view(&self) -> IcedElement<'_> {
        let pos = self
            .position
            .t
            .as_ref()
            .map(|p| p.0)
            .unwrap_or(widget::tooltip::Position::Bottom);
        let mut tt = widget::Tooltip::new(self.child.view(), self.tip.view(), pos);
        if let Some(Some(g)) = self.gap.t {
            tt = tt.gap(g as f32);
        }
        tt.into()
    }
}