graphix-package-tui 0.9.0

A dataflow language for UIs and network programming, TUI package
Documentation
use super::{gauge::clamp_ratio, into_borrowed_line, LineV, StyleV, TuiW, TuiWidget};
use anyhow::{Context, Result};
use arcstr::ArcStr;
use async_trait::async_trait;
use crossterm::event::Event;
use graphix_compiler::expr::ExprId;
use graphix_rt::{GXExt, GXHandle, TRef};
use netidx::publisher::Value;
use ratatui::{layout::Rect, widgets::LineGauge, Frame};
use tokio::try_join;

pub(super) struct LineGaugeW<X: GXExt> {
    filled_style: TRef<X, Option<StyleV>>,
    filled_symbol: TRef<X, Option<ArcStr>>,
    label: TRef<X, Option<LineV>>,
    ratio: TRef<X, f64>,
    style: TRef<X, Option<StyleV>>,
    unfilled_style: TRef<X, Option<StyleV>>,
    unfilled_symbol: TRef<X, Option<ArcStr>>,
    last_clamp_warning: Option<u64>,
}

impl<X: GXExt> LineGaugeW<X> {
    pub(super) async fn compile(gx: GXHandle<X>, v: Value) -> Result<TuiW> {
        let [(_, filled_style), (_, filled_symbol), (_, label), (_, ratio), (_, style), (_, unfilled_style), (_, unfilled_symbol)] =
            v.cast_to::<[(ArcStr, u64); 7]>()?;
        let (
            filled_style,
            filled_symbol,
            label,
            ratio,
            style,
            unfilled_style,
            unfilled_symbol,
        ) = try_join! {
            gx.compile_ref(filled_style),
            gx.compile_ref(filled_symbol),
            gx.compile_ref(label),
            gx.compile_ref(ratio),
            gx.compile_ref(style),
            gx.compile_ref(unfilled_style),
            gx.compile_ref(unfilled_symbol)
        }?;
        Ok(Box::new(Self {
            filled_style: TRef::new(filled_style)
                .context("line_gauge tref filled_style")?,
            filled_symbol: TRef::new(filled_symbol)
                .context("line_gauge tref filled_symbol")?,
            label: TRef::new(label).context("line_gauge tref label")?,
            ratio: TRef::new(ratio).context("line_gauge tref ratio")?,
            style: TRef::new(style).context("line_gauge tref style")?,
            unfilled_style: TRef::new(unfilled_style)
                .context("line_gauge tref unfilled_style")?,
            unfilled_symbol: TRef::new(unfilled_symbol)
                .context("line_gauge tref unfilled_symbol")?,
            last_clamp_warning: None,
        }))
    }
}

#[async_trait]
impl<X: GXExt> TuiWidget for LineGaugeW<X> {
    async fn handle_event(&mut self, _e: Event, _v: Value) -> Result<()> {
        Ok(())
    }

    async fn handle_update(&mut self, id: ExprId, v: Value) -> Result<()> {
        let Self {
            filled_style,
            filled_symbol,
            label,
            ratio,
            style,
            unfilled_style,
            unfilled_symbol,
            last_clamp_warning: _,
        } = self;
        filled_style.update(id, &v).context("line_gauge update filled_style")?;
        filled_symbol.update(id, &v).context("line_gauge update filled_symbol")?;
        label.update(id, &v).context("line_gauge update label")?;
        ratio.update(id, &v).context("line_gauge update ratio")?;
        style.update(id, &v).context("line_gauge update style")?;
        unfilled_style.update(id, &v).context("line_gauge update unfilled_style")?;
        unfilled_symbol.update(id, &v).context("line_gauge update unfilled_symbol")?;
        Ok(())
    }

    fn draw(&mut self, frame: &mut Frame, rect: Rect) -> Result<()> {
        let Self {
            filled_style,
            filled_symbol,
            label,
            ratio,
            style,
            unfilled_style,
            unfilled_symbol,
            last_clamp_warning,
        } = self;
        let raw = ratio.t.unwrap_or(0.0);
        let r = clamp_ratio("line_gauge", last_clamp_warning, raw);
        let mut g = LineGauge::default().ratio(r);
        if let Some(Some(LineV(l))) = &label.t {
            g = g.label(into_borrowed_line(l));
        }
        if let Some(Some(s)) = &filled_symbol.t {
            g = g.filled_symbol(&*s);
        }
        if let Some(Some(s)) = &style.t {
            g = g.style(s.0);
        }
        if let Some(Some(s)) = &filled_style.t {
            g = g.filled_style(s.0);
        }
        if let Some(Some(s)) = &unfilled_style.t {
            g = g.unfilled_style(s.0);
        }
        if let Some(Some(s)) = &unfilled_symbol.t {
            g = g.unfilled_symbol(s);
        }
        frame.render_widget(g, rect);
        Ok(())
    }
}