1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use hashbrown::{hash_map::Entry, HashSet};

use vizia_storage::Tree;

use crate::{
    entity::Entity,
    resource::{ImageOrSvg, ImageRetentionPolicy, ResourceManager, StoredImage},
    style::Style,
};

use super::{Context, ContextProxy, EventProxy};

/// A context used when loading images.
pub struct ResourceContext<'a> {
    pub(crate) current: Entity,
    pub(crate) event_proxy: &'a Option<Box<dyn EventProxy>>,
    pub(crate) resource_manager: &'a mut ResourceManager,
    pub(crate) style: &'a mut Style,
    pub(crate) tree: &'a Tree<Entity>,
}

impl<'a> ResourceContext<'a> {
    pub fn new(cx: &'a mut Context) -> Self {
        Self {
            current: cx.current,
            event_proxy: &cx.event_proxy,
            resource_manager: &mut cx.resource_manager,
            style: &mut cx.style,
            tree: &cx.tree,
        }
    }

    pub fn spawn<F>(&self, target: F)
    where
        F: 'static + Send + FnOnce(&mut ContextProxy),
    {
        let mut cxp = ContextProxy {
            current: self.current,
            event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
        };

        std::thread::spawn(move || target(&mut cxp));
    }

    pub fn load_image(
        &mut self,
        path: String,
        image: skia_safe::Image,
        policy: ImageRetentionPolicy,
    ) {
        let id = if let Some(image_id) = self.resource_manager.image_ids.get(&path) {
            *image_id
        } else {
            self.resource_manager.image_id_manager.create()
        };

        match self.resource_manager.images.entry(id) {
            Entry::Occupied(mut occ) => {
                occ.get_mut().image = ImageOrSvg::Image(image);
                occ.get_mut().dirty = true;
                occ.get_mut().retention_policy = policy;
            }
            Entry::Vacant(vac) => {
                vac.insert(StoredImage {
                    image: ImageOrSvg::Image(image),
                    retention_policy: policy,
                    used: true,
                    dirty: false,
                    observers: HashSet::new(),
                });
            }
        }
        self.style.needs_relayout();
    }
}