graphix_package_gui/widgets/
image.rs1use super::{GuiW, GuiWidget, IcedElement};
2use crate::types::{ContentFitV, ImageSourceV, LengthV};
3use anyhow::{Context, Result};
4use arcstr::ArcStr;
5use graphix_compiler::expr::ExprId;
6use graphix_rt::{GXExt, GXHandle, TRef};
7use iced_widget as widget;
8use netidx::publisher::Value;
9use tokio::try_join;
10
11fn make_handle(source: &ImageSourceV) -> ImageHandle {
12 if source.is_svg() {
13 ImageHandle::Svg(source.to_svg_handle())
14 } else {
15 ImageHandle::Raster(source.to_handle())
16 }
17}
18
19enum ImageHandle {
20 Raster(iced_core::image::Handle),
21 Svg(iced_core::svg::Handle),
22}
23
24pub(crate) struct ImageW<X: GXExt> {
25 source: TRef<X, ImageSourceV>,
26 handle: Option<ImageHandle>,
27 width: TRef<X, LengthV>,
28 height: TRef<X, LengthV>,
29 content_fit: TRef<X, ContentFitV>,
30}
31
32impl<X: GXExt> ImageW<X> {
33 pub(crate) async fn compile(gx: GXHandle<X>, source: Value) -> Result<GuiW<X>> {
34 let [(_, content_fit), (_, height), (_, src), (_, width)] =
35 source.cast_to::<[(ArcStr, u64); 4]>().context("image flds")?;
36 let (content_fit, height, src, width) = try_join! {
37 gx.compile_ref(content_fit),
38 gx.compile_ref(height),
39 gx.compile_ref(src),
40 gx.compile_ref(width),
41 }?;
42 let source = TRef::new(src).context("image tref source")?;
43 let handle = source.t.as_ref().map(make_handle);
44 Ok(Box::new(Self {
45 source,
46 handle,
47 width: TRef::new(width).context("image tref width")?,
48 height: TRef::new(height).context("image tref height")?,
49 content_fit: TRef::new(content_fit).context("image tref content_fit")?,
50 }))
51 }
52}
53
54impl<X: GXExt> GuiWidget<X> for ImageW<X> {
55 fn handle_update(
56 &mut self,
57 _rt: &tokio::runtime::Handle,
58 id: ExprId,
59 v: &Value,
60 ) -> Result<bool> {
61 let mut changed = false;
62 if self.source.update(id, v).context("image update source")?.is_some() {
63 self.handle = self.source.t.as_ref().map(make_handle);
64 changed = true;
65 }
66 changed |= self.width.update(id, v).context("image update width")?.is_some();
67 changed |= self.height.update(id, v).context("image update height")?.is_some();
68 changed |=
69 self.content_fit.update(id, v).context("image update content_fit")?.is_some();
70 Ok(changed)
71 }
72
73 fn view(&self) -> IcedElement<'_> {
74 let width = self.width.t.as_ref().map(|w| w.0);
75 let height = self.height.t.as_ref().map(|h| h.0);
76 let content_fit = self.content_fit.t.as_ref().map(|cf| cf.0);
77 match &self.handle {
78 Some(ImageHandle::Svg(h)) => {
79 let mut s = widget::Svg::new(h.clone());
80 if let Some(w) = width {
81 s = s.width(w);
82 }
83 if let Some(h) = height {
84 s = s.height(h);
85 }
86 if let Some(cf) = content_fit {
87 s = s.content_fit(cf);
88 }
89 s.into()
90 }
91 handle => {
92 let h = match handle {
93 Some(ImageHandle::Raster(h)) => h.clone(),
94 _ => iced_core::image::Handle::from_path(""),
95 };
96 let mut img = widget::Image::new(h);
97 if let Some(w) = width {
98 img = img.width(w);
99 }
100 if let Some(h) = height {
101 img = img.height(h);
102 }
103 if let Some(cf) = content_fit {
104 img = img.content_fit(cf);
105 }
106 img.into()
107 }
108 }
109 }
110}