From 592b6f04cddbeef7281e2e8057b159156ba2248d Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Tue, 27 Feb 2024 13:41:11 +0100 Subject: [PATCH] add small utilities --- rusalka/src/nodes/mod.rs | 3 +++ ui/src/lib.rs | 1 + ui/src/nodes/image.rs | 23 +++++++++++++++++++++++ ui/src/nodes/layout.rs | 14 ++++++++++++++ ui/src/nodes/mod.rs | 17 +++++++++++++++-- ui/src/nodes/text.rs | 27 +++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 2 deletions(-) diff --git a/rusalka/src/nodes/mod.rs b/rusalka/src/nodes/mod.rs index e5dad21..bc2088c 100644 --- a/rusalka/src/nodes/mod.rs +++ b/rusalka/src/nodes/mod.rs @@ -9,6 +9,9 @@ pub fn detach(node: &SharedNode) { } pub fn insert(parent: &SharedNode, node: &SharedNode, before: Option<&SharedNode>) { + if node.read().unwrap().parent().is_some() && !Arc::ptr_eq(&node.read().unwrap().parent().unwrap(), parent) { + detach(node); + } match before { Some(before) => { parent.write().unwrap().add_child_before(node.clone(), before).unwrap(); diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 2760abf..a49e70d 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -37,6 +37,7 @@ pub use cosmic_text; pub type CurrentRenderer = OpenGl; pub type SharedNode = Arc>; +pub type WeakSharedNode = Weak>; type WeakNode = Weak>; type NodePtr = Option>; type NodeLayoutMap = PtrWeakKeyHashMap>, taffy::tree::NodeId>; diff --git a/ui/src/nodes/image.rs b/ui/src/nodes/image.rs index 221c742..33ebc3b 100644 --- a/ui/src/nodes/image.rs +++ b/ui/src/nodes/image.rs @@ -51,6 +51,23 @@ pub struct Image { pub parent: Option } +impl Image { + pub fn new(image: ImageLoad) -> Image { + Image { + image, + ..Default::default() + } + } + pub fn radius(mut self, radius: f32) -> Image { + self.radius = radius; + self + } + pub fn style(mut self, style: Style) -> Image { + self.style = style; + self + } +} + lazy_static::lazy_static! { pub static ref IMAGES_TO_UNLOAD: Mutex> = Mutex::new(Vec::new()); } @@ -65,6 +82,12 @@ impl Node for Image { } fn prepare_render(&mut self, context: &mut RenderContext) { + if let Ok(mut images_to_unload) = IMAGES_TO_UNLOAD.try_lock() { + for image in images_to_unload.iter() { + context.canvas.delete_image(*image); + } + images_to_unload.clear(); + } match &self.image { ImageLoad::LoadFile(_, _) => { let image = mem::replace(&mut self.image, ImageLoad::Error(ErrorKind::UnknownError)); diff --git a/ui/src/nodes/layout.rs b/ui/src/nodes/layout.rs index 50f9e69..37768dc 100644 --- a/ui/src/nodes/layout.rs +++ b/ui/src/nodes/layout.rs @@ -1,4 +1,5 @@ use std::fmt::{Debug, Formatter}; +use std::sync::{Arc, RwLock}; use crate::{nodes::{Node, NodeChildren, Style}, events::handler::EventHandlerDatabase, WeakNode, SharedNode}; use taffy::style::Dimension; @@ -20,6 +21,19 @@ impl Layout { parent: None } } + pub fn empty() -> Layout { + Layout { + style: Style::default(), + children: NodeChildren::default(), + events: EventHandlerDatabase::default(), + parent: None + } + } + + pub fn style(mut self, style: Style) -> Layout { + self.style = style; + self + } } impl Debug for Layout { diff --git a/ui/src/nodes/mod.rs b/ui/src/nodes/mod.rs index d567abe..da980a7 100644 --- a/ui/src/nodes/mod.rs +++ b/ui/src/nodes/mod.rs @@ -1,11 +1,12 @@ pub mod layout; +pub mod empty; pub mod primitives; pub mod image; pub mod text; pub mod text_render_cache; use std::fmt::Debug; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use femtovg::{Canvas, Color}; use crate::events::Location; use crate::events::handler::InnerEventHandlerDataset; @@ -171,8 +172,10 @@ pub trait Node: Debug { /// Add a child to the node at the given index. If the node does not support children, returns error ChildrenNotSupported. /// Adding the same child multiple times or to multiple parents is not supported and will result in undefined behavior. /// Arc> does **NOT** mean that it's safe to add the same node multiple times. + /// + /// Note that this doesn't set the parent of the child. You need to do that manually. /// - /// Implementors can check [`Node::has_child`] to check if the child already exists. Default implementation thros [`ChildAddError::ChildrenNotSupported`]. + /// Implementors can check [`Node::has_child`] to check if the child already exists. Default implementation throws [`ChildAddError::ChildrenNotSupported`]. /// Adding a child that already exists should move that child to the new position. fn add_child_at(&mut self, _child: SharedNode, _index: usize) -> Result<(), ChildAddError> { Err(ChildAddError::ChildrenNotSupported) } @@ -266,6 +269,16 @@ pub trait Node: Debug { fn resize(&mut self, _width: f32, _height: f32) {} } +pub trait ToShared { + fn to_shared(self) -> SharedNode; +} + +impl ToShared for T { + fn to_shared(self) -> SharedNode { + Arc::new(RwLock::new(self)) + } +} + /// Runs event handlers for the given path /// The target element should be the last one in path (event handlers are ran in reverse order) pub(crate) fn run_event_handlers(path: Vec, event: crate::events::NodeEvent) { diff --git a/ui/src/nodes/text.rs b/ui/src/nodes/text.rs index 7c25443..31975c9 100644 --- a/ui/src/nodes/text.rs +++ b/ui/src/nodes/text.rs @@ -1,4 +1,5 @@ use std::fmt::Debug; +use std::sync::{Arc, RwLock}; use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM}; use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style, MeasureContext, RenderContext}; use cosmic_text::{Attrs, Buffer, Family, Metrics, Shaping, Stretch}; @@ -17,6 +18,32 @@ pub struct Text { pub paint: Paint } +impl Text { + pub fn new(text: String, metrics: Metrics) -> Text { + Text { + text, + metrics, + ..Default::default() + } + } + pub fn text(mut self, text: String) -> Self { + self.text = text; + self + } + pub fn metrics(mut self, metrics: Metrics) -> Self { + self.metrics = metrics; + self + } + pub fn paint(mut self, paint: Paint) -> Self { + self.paint = paint; + self + } + pub fn style(mut self, style: Style) -> Self { + self.style = style; + self + } +} + impl Node for Text { fn style(&self) -> &Style { &self.style