use std::{
collections::HashMap,
sync::{
atomic::{AtomicBool, AtomicUsize},
Arc, Once, RwLock,
},
};
use indextree::NodeId;
use crate::{
layers::layer::{state::LayerDataProps, ModelLayer},
prelude::*,
taffy::Style,
types::Point,
};
use super::{
node::SceneNode, scene::Scene, storage::TreeStorageNode, AnimatedNodeChange, AnimationRef,
AnimationState, Engine, NodeRef, TransactionCallback, TransactionRef,
};
#[derive(Clone)]
pub struct LayersEngine {
pub(crate) engine: Arc<Engine>,
}
impl std::fmt::Debug for LayersEngine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LayersEngine").finish()
}
}
pub(crate) static INIT: Once = Once::new();
pub(crate) static ENGINE_ID: AtomicUsize = AtomicUsize::new(0);
pub(crate) static mut ENGINES: Option<RwLock<HashMap<usize, Arc<Engine>>>> = None;
pub(crate) fn initialize_engines() {
unsafe {
ENGINES = Some(RwLock::new(HashMap::new()));
}
}
impl LayersEngine {
pub fn new(width: f32, height: f32) -> Self {
let engines = unsafe {
INIT.call_once(initialize_engines);
ENGINES.as_ref().unwrap()
};
let id = ENGINE_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let new_engine = Engine::create(id, width, height);
engines.write().unwrap().insert(id, new_engine.clone());
Self { engine: new_engine }
}
pub fn set_scene_size(&self, width: f32, height: f32) {
self.engine.scene.set_size(width, height);
}
pub fn new_layer(&self) -> Layer {
let model = Arc::new(ModelLayer::default());
let mut lt = self.engine.layout_tree.write().unwrap();
let layout = lt.new_leaf(Style::default()).unwrap();
Layer {
engine: self.engine.clone(),
model,
id: Arc::new(RwLock::new(None)),
key: Arc::new(RwLock::new(String::new())),
layout_node_id: layout,
hidden: Arc::new(AtomicBool::new(false)),
pointer_events: Arc::new(AtomicBool::new(true)),
image_cache: Arc::new(AtomicBool::new(false)),
picture_cache: Arc::new(AtomicBool::new(true)),
state: Arc::new(RwLock::new(LayerDataProps::default())),
effect: Arc::new(RwLock::new(None)),
}
}
pub fn new_animation(&self, transition: Transition, autostart: bool) -> AnimationRef {
self.engine
.add_animation_from_transition(transition, autostart)
}
pub fn attach_animation(&self, transaction: TransactionRef, animation: AnimationRef) {
self.engine.attach_animation(transaction, animation);
}
pub fn start_animation(&self, animation: AnimationRef, delay: f32) {
self.engine.start_animation(animation, delay);
}
pub fn add_animated_changes(
&self,
animated_changes: &[AnimatedNodeChange],
animation: impl Into<Option<AnimationRef>>,
) -> Vec<TransactionRef> {
self.engine.schedule_changes(animated_changes, animation)
}
pub fn update(&self, dt: f32) -> bool {
self.engine.update(dt)
}
pub fn update_nodes(&self) -> skia_safe::Rect {
self.engine.update_nodes()
}
pub fn scene_add_layer(&self, layer: impl Into<Layer>) -> NodeRef {
self.engine.scene_add_layer(layer, None)
}
pub fn scene_add_layer_to(
&self,
layer: impl Into<Layer>,
parent: impl Into<Option<NodeRef>>,
) -> NodeRef {
let parent = parent.into();
self.engine.scene_add_layer(layer, parent)
}
pub fn scene_add_layer_to_positioned(
&self,
layer: impl Into<Layer>,
parent: impl Into<Option<NodeRef>>,
) -> NodeRef {
let parent = parent.into();
self.engine.scene_add_layer_to_positioned(layer, parent)
}
pub fn scene_remove_layer(&self, node: impl Into<Option<NodeRef>>) {
if let Some(node) = node.into() {
self.engine.mark_for_delete(node);
}
}
pub fn scene_set_root(&self, layer: impl Into<Layer>) -> NodeRef {
self.engine.scene_set_root(layer)
}
pub fn scene_get_node(&self, node: &NodeRef) -> Option<TreeStorageNode<SceneNode>> {
self.engine.scene_get_node(node)
}
pub fn scene_get_node_parent(&self, node: &NodeRef) -> Option<NodeRef> {
self.engine.scene_get_node_parent(node)
}
pub fn scene(&self) -> &Arc<Scene> {
&self.engine.scene
}
pub fn scene_root(&self) -> Option<NodeRef> {
*self.engine.scene_root.read().unwrap()
}
pub fn scene_root_layer(&self) -> Option<SceneNode> {
let root_id = self.scene_root()?;
let node = self.scene_get_node(&root_id)?;
Some(node.get().clone())
}
pub fn scene_layer_at(&self, point: Point) -> Option<NodeRef> {
self.engine.layer_at(point)
}
pub fn damage(&self) -> skia_safe::Rect {
*self.engine.damage.read().unwrap()
}
#[profiling::function]
pub fn clear_damage(&self) {
*self.engine.damage.write().unwrap() = skia_safe::Rect::default();
}
pub fn pointer_move(&self, point: impl Into<Point>, root_id: impl Into<Option<NodeId>>) {
self.engine.pointer_move(point, root_id);
}
pub fn pointer_button_down(&self) {
self.engine.pointer_button_down();
}
pub fn pointer_button_up(&self) {
self.engine.pointer_button_up();
}
pub fn current_hover(&self) -> Option<NodeRef> {
self.engine.current_hover()
}
pub fn get_pointer_position(&self) -> Point {
self.engine.get_pointer_position()
}
pub fn get_transaction(&self, transaction: TransactionRef) -> Option<AnimatedNodeChange> {
self.engine.get_transaction_for_value(transaction.value_id)
}
pub fn get_transaction_for_value(&self, value_id: usize) -> Option<AnimatedNodeChange> {
self.engine.get_transaction_for_value(value_id)
}
pub fn get_animation(&self, animation: AnimationRef) -> Option<AnimationState> {
self.engine.get_animation(animation)
}
pub fn on_finish<F: Into<TransactionCallback>>(
&self,
transaction: TransactionRef,
handler: F,
once: bool,
) {
self.engine.on_finish(transaction, handler, once);
}
pub fn on_update<F: Into<TransactionCallback>>(
&self,
transaction: TransactionRef,
handler: F,
once: bool,
) {
self.engine.on_update(transaction, handler, once);
}
pub fn on_start<F: Into<TransactionCallback>>(
&self,
transaction: TransactionRef,
handler: F,
once: bool,
) {
self.engine.on_start(transaction, handler, once);
}
pub fn on_update_value<F: Into<TransactionCallback>>(
&self,
value_id: usize,
handler: F,
once: bool,
) {
let mut handler = handler.into();
handler.once = once;
self.engine.on_update_value(value_id, handler, once);
}
pub fn on_start_value<F: Into<TransactionCallback>>(
&self,
value_id: usize,
handler: F,
once: bool,
) {
let mut handler = handler.into();
handler.once = once;
self.engine.on_start_value(value_id, handler, once);
}
pub fn cancel_animation(&self, animation: AnimationRef) {
self.engine.cancel_animation(animation);
}
#[cfg(feature = "debugger")]
pub fn start_debugger(&self) {
layers_debug_server::start_debugger_server(self.engine.clone());
}
pub fn layer_as_content(&self, layer: &Layer) -> ContentDrawFunction {
let layer_ref = layer.clone();
let engine_ref = self.clone();
let draw_function = move |c: &skia::Canvas, w: f32, h: f32| {
let id = layer_ref.id().unwrap();
let scene = engine_ref.scene();
scene.with_arena(|arena| {
render_node_tree(id, arena, c, 1.0);
});
skia::Rect::from_xywh(0.0, 0.0, w, h)
};
ContentDrawFunction::from(draw_function)
}
}