mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 06:38:03 +08:00
Add Layer and Artboard node definitions and underlying data structures (#1204)
* Add basic node defenitions * Code review * change widget code * Artboard node changes --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
committed by
Keavon Chambers
parent
7e1b452757
commit
4e0c673a35
140
node-graph/gcore/src/graphic_element.rs
Normal file
140
node-graph/gcore/src/graphic_element.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
use crate::raster::{BlendMode, ImageFrame};
|
||||
use crate::vector::VectorData;
|
||||
use crate::{Color, Node};
|
||||
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use glam::IVec2;
|
||||
use node_macro::node_fn;
|
||||
|
||||
/// A list of [`GraphicElement`]s
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct GraphicGroup(Vec<GraphicElement>);
|
||||
|
||||
/// Internal data for a [`GraphicElement`]. Can be [`VectorData`], [`ImageFrame`], text, or a nested [`GraphicGroup`]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum GraphicElementData {
|
||||
VectorShape(Box<VectorData>),
|
||||
ImageFrame(ImageFrame<Color>),
|
||||
Text(String),
|
||||
GraphicGroup(GraphicGroup),
|
||||
Artboard(Artboard),
|
||||
}
|
||||
|
||||
/// A named [`GraphicElementData`] with a blend mode, opacity, as well as visibility, locked, and collapsed states.
|
||||
#[derive(Clone, Debug, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct GraphicElement {
|
||||
pub name: String,
|
||||
pub blend_mode: BlendMode,
|
||||
/// In range 0..=1
|
||||
pub opacity: f32,
|
||||
pub visible: bool,
|
||||
pub locked: bool,
|
||||
pub collapsed: bool,
|
||||
pub graphic_element_data: GraphicElementData,
|
||||
}
|
||||
|
||||
/// Some [`ArtboardData`] with some optional clipping bounds that can be exported.
|
||||
/// Similar to an Inkscape page: https://media.inkscape.org/media/doc/release_notes/1.2/Inkscape_1.2.html#Page_tool
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Artboard {
|
||||
pub graphic_group: GraphicGroup,
|
||||
pub bounds: Option<[IVec2; 2]>,
|
||||
}
|
||||
|
||||
pub struct ConstructLayerNode<Name, BlendMode, Opacity, Visible, Locked, Collapsed, Stack> {
|
||||
name: Name,
|
||||
blend_mode: BlendMode,
|
||||
opacity: Opacity,
|
||||
visible: Visible,
|
||||
locked: Locked,
|
||||
collapsed: Collapsed,
|
||||
stack: Stack,
|
||||
}
|
||||
|
||||
#[node_fn(ConstructLayerNode)]
|
||||
fn construct_layer<Data: Into<GraphicElementData>>(
|
||||
graphic_element_data: Data,
|
||||
name: String,
|
||||
blend_mode: BlendMode,
|
||||
opacity: f32,
|
||||
visible: bool,
|
||||
locked: bool,
|
||||
collapsed: bool,
|
||||
mut stack: GraphicGroup,
|
||||
) -> GraphicGroup {
|
||||
stack.push(GraphicElement {
|
||||
name,
|
||||
blend_mode,
|
||||
opacity: opacity / 100.,
|
||||
visible,
|
||||
locked,
|
||||
collapsed,
|
||||
graphic_element_data: graphic_element_data.into(),
|
||||
});
|
||||
stack
|
||||
}
|
||||
|
||||
pub struct ConstructArtboardNode<Bounds> {
|
||||
bounds: Bounds,
|
||||
}
|
||||
|
||||
#[node_fn(ConstructArtboardNode)]
|
||||
fn construct_artboard(graphic_group: GraphicGroup, bounds: Option<[IVec2; 2]>) -> Artboard {
|
||||
Artboard { graphic_group, bounds }
|
||||
}
|
||||
|
||||
impl From<ImageFrame<Color>> for GraphicElementData {
|
||||
fn from(image_frame: ImageFrame<Color>) -> Self {
|
||||
GraphicElementData::ImageFrame(image_frame)
|
||||
}
|
||||
}
|
||||
impl From<VectorData> for GraphicElementData {
|
||||
fn from(vector_data: VectorData) -> Self {
|
||||
GraphicElementData::VectorShape(Box::new(vector_data))
|
||||
}
|
||||
}
|
||||
impl From<GraphicGroup> for GraphicElementData {
|
||||
fn from(graphic_group: GraphicGroup) -> Self {
|
||||
GraphicElementData::GraphicGroup(graphic_group)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Artboard> for GraphicElementData {
|
||||
fn from(artboard: Artboard) -> Self {
|
||||
GraphicElementData::Artboard(artboard)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for GraphicGroup {
|
||||
type Target = Vec<GraphicElement>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl DerefMut for GraphicGroup {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicGroup {
|
||||
pub const EMPTY: Self = Self(Vec::new());
|
||||
}
|
||||
|
||||
impl core::hash::Hash for GraphicElement {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.name.hash(state);
|
||||
self.blend_mode.hash(state);
|
||||
self.opacity.to_bits().hash(state);
|
||||
self.visible.hash(state);
|
||||
self.locked.hash(state);
|
||||
self.collapsed.hash(state);
|
||||
self.graphic_element_data.hash(state);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,10 @@ pub mod raster;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod transform;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
mod graphic_element;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use graphic_element::*;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod vector;
|
||||
|
||||
|
||||
@@ -17,6 +17,15 @@ pub struct VectorData {
|
||||
pub mirror_angle: Vec<ManipulatorGroupId>,
|
||||
}
|
||||
|
||||
impl core::hash::Hash for VectorData {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.subpaths.hash(state);
|
||||
self.transform.to_cols_array().iter().for_each(|x| x.to_bits().hash(state));
|
||||
self.style.hash(state);
|
||||
self.mirror_angle.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl VectorData {
|
||||
/// An empty subpath with no data, an identity transform, and a black fill.
|
||||
pub const fn empty() -> Self {
|
||||
|
||||
Reference in New Issue
Block a user