use crate::raster::Image; use crate::raster_types::{CPU, RasterDataTable}; use crate::registry::types::Percentage; use crate::vector::VectorDataTable; use crate::{BlendMode, Color, Ctx, GraphicElement, GraphicGroupTable}; pub(super) trait MultiplyAlpha { fn multiply_alpha(&mut self, factor: f64); } impl MultiplyAlpha for Color { fn multiply_alpha(&mut self, factor: f64) { *self = Color::from_rgbaf32_unchecked(self.r(), self.g(), self.b(), (self.a() * factor as f32).clamp(0., 1.)) } } impl MultiplyAlpha for VectorDataTable { fn multiply_alpha(&mut self, factor: f64) { for instance in self.instance_mut_iter() { instance.alpha_blending.opacity *= factor as f32; } } } impl MultiplyAlpha for GraphicGroupTable { fn multiply_alpha(&mut self, factor: f64) { for instance in self.instance_mut_iter() { instance.alpha_blending.opacity *= factor as f32; } } } impl MultiplyAlpha for RasterDataTable where GraphicElement: From>, { fn multiply_alpha(&mut self, factor: f64) { for instance in self.instance_mut_iter() { instance.alpha_blending.opacity *= factor as f32; } } } pub(super) trait MultiplyFill { fn multiply_fill(&mut self, factor: f64); } impl MultiplyFill for Color { fn multiply_fill(&mut self, factor: f64) { *self = Color::from_rgbaf32_unchecked(self.r(), self.g(), self.b(), (self.a() * factor as f32).clamp(0., 1.)) } } impl MultiplyFill for VectorDataTable { fn multiply_fill(&mut self, factor: f64) { for instance in self.instance_mut_iter() { instance.alpha_blending.fill *= factor as f32; } } } impl MultiplyFill for GraphicGroupTable { fn multiply_fill(&mut self, factor: f64) { for instance in self.instance_mut_iter() { instance.alpha_blending.fill *= factor as f32; } } } impl MultiplyFill for RasterDataTable { fn multiply_fill(&mut self, factor: f64) { for instance in self.instance_mut_iter() { instance.alpha_blending.fill *= factor as f32; } } } trait SetBlendMode { fn set_blend_mode(&mut self, blend_mode: BlendMode); } impl SetBlendMode for VectorDataTable { fn set_blend_mode(&mut self, blend_mode: BlendMode) { for instance in self.instance_mut_iter() { instance.alpha_blending.blend_mode = blend_mode; } } } impl SetBlendMode for GraphicGroupTable { fn set_blend_mode(&mut self, blend_mode: BlendMode) { for instance in self.instance_mut_iter() { instance.alpha_blending.blend_mode = blend_mode; } } } impl SetBlendMode for RasterDataTable { fn set_blend_mode(&mut self, blend_mode: BlendMode) { for instance in self.instance_mut_iter() { instance.alpha_blending.blend_mode = blend_mode; } } } trait SetClip { fn set_clip(&mut self, clip: bool); } impl SetClip for VectorDataTable { fn set_clip(&mut self, clip: bool) { for instance in self.instance_mut_iter() { instance.alpha_blending.clip = clip; } } } impl SetClip for GraphicGroupTable { fn set_clip(&mut self, clip: bool) { for instance in self.instance_mut_iter() { instance.alpha_blending.clip = clip; } } } impl SetClip for RasterDataTable { fn set_clip(&mut self, clip: bool) { for instance in self.instance_mut_iter() { instance.alpha_blending.clip = clip; } } } #[node_macro::node(category("Style"))] fn blend_mode( _: impl Ctx, #[implementations( GraphicGroupTable, VectorDataTable, RasterDataTable, )] mut value: T, blend_mode: BlendMode, ) -> T { // TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or Instance) rather than applying to each row in its own table, which produces the undesired result value.set_blend_mode(blend_mode); value } #[node_macro::node(category("Style"))] fn opacity( _: impl Ctx, #[implementations( GraphicGroupTable, VectorDataTable, RasterDataTable, )] mut value: T, #[default(100.)] opacity: Percentage, ) -> T { // TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or Instance) rather than applying to each row in its own table, which produces the undesired result value.multiply_alpha(opacity / 100.); value } #[node_macro::node(category("Style"))] fn blending( _: impl Ctx, #[implementations( GraphicGroupTable, VectorDataTable, RasterDataTable, )] mut value: T, blend_mode: BlendMode, #[default(100.)] opacity: Percentage, #[default(100.)] fill: Percentage, #[default(false)] clip: bool, ) -> T { // TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or Instance) rather than applying to each row in its own table, which produces the undesired result value.set_blend_mode(blend_mode); value.multiply_alpha(opacity / 100.); value.multiply_fill(fill / 100.); value.set_clip(clip); value }