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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! The Scene is the data structure to represent the tree of nodes to be rendered.
//! It enables the traversing and manipulation of the nodes.
//!
//! The scene is a tree of renderable nodes (implementing the `Renderable` trait).
//! The tree is stored in a memory arena using IndexTree, which allow fast read/write and thread safe parallel iterations.

use indextree::Arena;
use std::sync::{Arc, RwLock};
use taffy::prelude::NodeId as TaffyNode;
use tokio::{runtime::Handle, task::JoinError};

use crate::prelude::{Layer, Point};

use super::{
    node::{DrawCacheManagement, SceneNode},
    storage::{TreeStorage, TreeStorageId, TreeStorageNode},
    NodeRef,
};
pub struct Scene {
    pub(crate) nodes: TreeStorage<SceneNode>,
    pub size: RwLock<Point>,
}

impl Scene {
    pub fn new(width: f32, height: f32) -> Self {
        let nodes = TreeStorage::new();
        Self {
            nodes,
            size: RwLock::new(Point {
                x: width,
                y: height,
            }),
        }
    }
    pub fn set_size(&self, width: f32, height: f32) {
        let mut size = self.size.write().unwrap();
        *size = Point {
            x: width,
            y: height,
        };
    }
    pub(crate) fn create(width: f32, height: f32) -> Arc<Scene> {
        Arc::new(Self::new(width, height))
    }

    /// Append the child node to the parent node.
    ///
    /// The child node is first detached from the scene and then appended the new parent.
    /// After appending, the child node is marked as needing paint (NEEDS_PAINT).
    pub(crate) fn append_node_to(&self, child: NodeRef, parent: NodeRef) {
        self.with_arena_mut(|nodes| {
            let child = *child;
            child.detach(nodes);
            parent.append(child, nodes);
            let scene_node = nodes.get(child).unwrap().get();
            scene_node.set_need_repaint(true);

            let parent = *parent;
            let new_parent_node = nodes.get(parent).unwrap().get();
            new_parent_node.set_need_layout(true);
        });
    }

    pub(crate) fn prepend_node_to(&self, child: NodeRef, parent: NodeRef) {
        self.with_arena_mut(|nodes| {
            let child = *child;
            child.detach(nodes);
            parent.prepend(child, nodes);
            let scene_node = nodes.get(child).unwrap().get();
            scene_node.set_need_repaint(true);

            let parent = *parent;
            let new_parent_node = nodes.get(parent).unwrap().get();
            new_parent_node.set_need_layout(true);
        });
    }
    /// Add a new node to the scene
    fn insert_node(&self, node: &SceneNode, parent: Option<NodeRef>) -> NodeRef {
        let handle = Handle::current();
        let id = tokio::task::block_in_place(|| handle.block_on(self.nodes.insert(node.clone())));
        if let Some(parent) = parent {
            self.append_node_to(NodeRef(id), parent);
        }
        NodeRef(id)
    }

    pub async fn get_node(
        &self,
        id: impl Into<TreeStorageId>,
    ) -> Option<TreeStorageNode<SceneNode>> {
        let id = id.into();
        let scene_node = self.nodes.get(id).await;
        scene_node.filter(|node| !node.is_removed())
    }

    pub fn get_node_sync(
        &self,
        id: impl Into<TreeStorageId>,
    ) -> Option<TreeStorageNode<SceneNode>> {
        let id = id.into();
        let handle = Handle::current();
        let _ = handle.enter();
        let scene_node = tokio::task::block_in_place(|| handle.block_on(self.nodes.get(id)));
        scene_node.filter(|node| !node.is_removed())
    }

    pub fn add<R: Into<Layer>>(&self, renderable: R, layout: TaffyNode) -> NodeRef {
        let renderable: Layer = renderable.into();
        let node = SceneNode::with_renderable_and_layout(renderable, layout);
        self.insert_node(&node, None)
    }
    pub fn append<R: Into<Layer>>(
        &self,
        parent: Option<NodeRef>,
        renderable: R,
        layout: TaffyNode,
    ) -> NodeRef {
        let renderable: Layer = renderable.into();
        let node = SceneNode::with_renderable_and_layout(renderable, layout);
        self.insert_node(&node, parent)
    }
    pub(crate) fn remove(&self, id: impl Into<TreeStorageId>) {
        let id = id.into();
        let handle = Handle::current();
        tokio::task::block_in_place(|| handle.block_on(self.nodes.remove_at(&id)));
    }

    pub async fn with_arena_async<T, F>(&self, f: F) -> Result<T, JoinError>
    where
        T: Send + Sync + 'static,
        F: FnOnce(&Arena<SceneNode>) -> T + Send + 'static,
    {
        let arena_guard = self.nodes.data();
        let handle = Handle::current();
        let join = tokio::task::spawn_blocking(move || {
            let arena_guard = handle.block_on(arena_guard.read());
            f(&arena_guard)
        });
        join.await
    }

    pub fn with_arena<T: Send + Sync>(&self, f: impl FnOnce(&Arena<SceneNode>) -> T) -> T {
        let arena_guard = self.nodes.data();
        let handle = Handle::current();
        tokio::task::block_in_place(|| {
            let arena_guard = handle.block_on(arena_guard.read());
            f(&arena_guard)
        })
    }

    pub(crate) fn with_arena_mut<T>(&self, f: impl FnOnce(&mut Arena<SceneNode>) -> T) -> T {
        let arena_guard = self.nodes.data();
        let handle = Handle::current();
        tokio::task::block_in_place(|| {
            let mut arena_guard = handle.block_on(arena_guard.write());
            f(&mut arena_guard)
        })
    }
}