add image node

This commit is contained in:
Daniel Bulant 2024-02-20 22:21:50 +01:00
parent f7ad523459
commit 866a526605
3 changed files with 62 additions and 17 deletions

View file

@ -1,16 +1,27 @@
use std::fmt::Debug;
use femtovg::{ImageId, Paint, Path};
use std::{fmt::Debug, mem, path::PathBuf};
use femtovg::{Color, ErrorKind, ImageFlags, ImageId, Paint, Path};
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode};
use super::{Node, NodeChildren, Style};
#[derive(Debug)]
/// Simple image node.
/// This is basically just a wrapper around Rectangle node with a fill of type Paint::image.
/// Use that if you need more options.
/// Status of the image - when rendering, image node attempts to load the image and sets this status accordingly.
/// Changes this if you want to change the image. If the previous status was loaded, free the image.
/// In case the loading fails, image load status changes to Error and the node doesn't render.
pub enum ImageLoad {
LoadFile(PathBuf, ImageFlags),
// LoadArray(&[u8]),
LoadVec(Vec<u8>, ImageFlags),
Loaded(ImageId),
Error(ErrorKind)
}
#[derive(Debug)]
/// Image node.
/// Sadly doesn't implement `Default` because of the `ImageLoad` enum.
pub struct Image {
pub style: Style,
/// The image to be rendered. You are responsible for freeing the image data.
pub image: ImageId,
/// The image to be rendered.
pub image: ImageLoad,
/// Image width - note that you also have to set the style accordingly for it to render correctly, this is more about scaling the image
pub width: f32,
/// Image height - note that you also have to set the style accordingly for it to render correctly, this is more about scaling the image
@ -30,7 +41,33 @@ impl Node for Image {
None
}
fn render_pre_children(&self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
match &self.image {
ImageLoad::LoadFile(_, _) => {
let image = mem::replace(&mut self.image, ImageLoad::Error(ErrorKind::UnknownError));
if let ImageLoad::LoadFile(path, flags) = image {
match context.canvas.load_image_file(path, flags) {
Ok(image) => {
self.image = ImageLoad::Loaded(image);
},
Err(e) => {
self.image = ImageLoad::Error(e);
}
}
}
},
ImageLoad::LoadVec(data, flags) => {
match context.canvas.load_image_mem(data, *flags) {
Ok(image) => {
self.image = ImageLoad::Loaded(image);
},
Err(e) => {
self.image = ImageLoad::Error(e);
}
}
},
_ => {}
}
let mut path = Path::new();
path.rounded_rect(
0.,
@ -39,10 +76,18 @@ impl Node for Image {
layout.size.height,
self.radius
);
context.canvas.fill_path(
&path,
&Paint::image(self.image, 0., 0., self.width, self.height, 0., 1.)
);
match &self.image {
ImageLoad::Loaded(image) => {
context.canvas.fill_path(
&path,
&Paint::image(*image, 0., 0., self.width, self.height, 0., 1.)
);
},
ImageLoad::Error(_) => {
context.canvas.fill_path(&path, &Paint::color(Color::rgb(255, 0, 0)))
},
_ => unreachable!("We just loaded the image before, so it's either loaded or errored out.")
}
}
fn event_handlers(&self) -> Option<crate::events::handler::InnerEventHandlerDataset> {

View file

@ -110,10 +110,10 @@ pub trait Node: Debug {
/// Render the node, called before rendering it's children
/// Canvas considers 0, 0 to be top left corner (for location after layouting happens)
fn render_pre_children(&self, _context: &mut RenderContext, _layout: Layout) {}
fn render_pre_children(&mut self, _context: &mut RenderContext, _layout: Layout) {}
/// Render the node, called after rendering it's children
/// Canvas considers 0, 0 to be top left corner (for location after layouting happens)
fn render_post_children(&self, _context: &mut RenderContext, _layout: Layout) {}
fn render_post_children(&mut self, _context: &mut RenderContext, _layout: Layout) {}
/// Sets the parent node.
/// May be called multiple times with the same value.
@ -340,12 +340,12 @@ pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext)
}
}
drop(read_node);
sself.read().unwrap().render_pre_children(context, layout);
sself.write().unwrap().render_pre_children(context, layout);
if let Some(children) = sself.read().unwrap().children() {
for child in children {
render_recursively(child, context);
}
}
sself.read().unwrap().render_post_children(context, layout);
sself.write().unwrap().render_post_children(context, layout);
context.canvas.restore();
}

View file

@ -30,7 +30,7 @@ impl Node for Rectangle {
fn children(&self) -> Option<&NodeChildren> {
None
}
fn render_pre_children(&self, context: &mut RenderContext, layout: Layout) {
fn render_pre_children(&mut self, context: &mut RenderContext, layout: Layout) {
let mut path = Path::new();
path.rounded_rect(
0.,