use crate::{ div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId, ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, LayoutId, Pixels, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, StyleRefinement, Styled, ViewContext, }; use futures::FutureExt; use util::ResultExt; pub struct Img< V: 'static, I: ElementInteraction = StatelessInteraction, F: ElementFocus = FocusDisabled, > { base: Div, uri: Option, grayscale: bool, } pub fn img() -> Img, FocusDisabled> { Img { base: div(), uri: None, grayscale: false, } } impl Img where V: 'static, I: ElementInteraction, F: ElementFocus, { pub fn uri(mut self, uri: impl Into) -> Self { self.uri = Some(uri.into()); self } pub fn grayscale(mut self, grayscale: bool) -> Self { self.grayscale = grayscale; self } } impl Img, F> where F: ElementFocus, { pub fn id(self, id: impl Into) -> Img, F> { Img { base: self.base.id(id), uri: self.uri, grayscale: self.grayscale, } } } impl Component for Img where I: ElementInteraction, F: ElementFocus, { fn render(self) -> AnyElement { AnyElement::new(self) } } impl Element for Img where I: ElementInteraction, F: ElementFocus, { type ElementState = DivState; fn id(&self) -> Option { self.base.id() } fn initialize( &mut self, view_state: &mut V, element_state: Option, cx: &mut ViewContext, ) -> Self::ElementState { self.base.initialize(view_state, element_state, cx) } fn layout( &mut self, view_state: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { self.base.layout(view_state, element_state, cx) } fn paint( &mut self, bounds: Bounds, view: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) { cx.stack(0, |cx| { self.base.paint(bounds, view, element_state, cx); }); let style = self.base.compute_style(bounds, element_state, cx); let corner_radii = style.corner_radii; if let Some(uri) = self.uri.clone() { // eprintln!(">>> image_cache.get({uri}"); let image_future = cx.image_cache.get(uri.clone()); // eprintln!("<<< image_cache.get({uri}"); if let Some(data) = image_future .clone() .now_or_never() .and_then(ResultExt::log_err) { let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size()); cx.stack(1, |cx| { cx.paint_image(bounds, corner_radii, data, self.grayscale) .log_err() }); } else { cx.spawn(|_, mut cx| async move { if image_future.await.log_err().is_some() { cx.on_next_frame(|cx| cx.notify()); } }) .detach() } } } } impl Styled for Img where I: ElementInteraction, F: ElementFocus, { fn style(&mut self) -> &mut StyleRefinement { self.base.style() } } impl StatelessInteractive for Img where I: ElementInteraction, F: ElementFocus, { fn stateless_interaction(&mut self) -> &mut StatelessInteraction { self.base.stateless_interaction() } } impl StatefulInteractive for Img, F> where F: ElementFocus, { fn stateful_interaction(&mut self) -> &mut StatefulInteraction { self.base.stateful_interaction() } } impl Focusable for Img> where V: 'static, I: ElementInteraction, { fn focus_listeners(&mut self) -> &mut FocusListeners { self.base.focus_listeners() } fn set_focus_style(&mut self, style: StyleRefinement) { self.base.set_focus_style(style) } fn set_focus_in_style(&mut self, style: StyleRefinement) { self.base.set_focus_in_style(style) } fn set_in_focus_style(&mut self, style: StyleRefinement) { self.base.set_in_focus_style(style) } }