wayver's git archive


an obsidian renderer
git clone https://git.wayver.dev/sable

sable-canvas/src/node/group.rs@main

raw
Date Commit Message Author Files + -
2026-02-23 01:55 initial mvp wayverd 139 17808 0
...

1use std::path::PathBuf;
2
3use crate::{
4    NodeId, PixelCoordinate, PixelDimension,
5    color::Color,
6    node::{GenericNode, GenericNodeInfo},
7};
8
9/// A group node.
10#[derive(
11    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
12)]
13pub struct GroupNode {
14    #[serde(flatten)]
15    generic: GenericNode,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    label: Option<String>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    #[serde(flatten)]
20    background: Option<Background>,
21}
22
23impl GroupNode {
24    /// Creates a new [`GroupNode`].
25    #[allow(clippy::too_many_arguments)]
26    #[must_use]
27    pub const fn new(
28        id: NodeId,
29        x: PixelCoordinate,
30        y: PixelCoordinate,
31        width: PixelDimension,
32        height: PixelDimension,
33        color: Option<Color>,
34        label: Option<String>,
35        background: Option<Background>,
36    ) -> Self {
37        Self {
38            generic: GenericNode::new(id, x, y, width, height, color),
39            label,
40            background,
41        }
42    }
43
44    /// Returns the label of this [`GroupNode`].
45    #[must_use]
46    pub const fn label(&self) -> Option<&String> {
47        self.label.as_ref()
48    }
49
50    /// Returns the background of this [`GroupNode`].
51    #[must_use]
52    pub const fn background(&self) -> Option<&Background> {
53        self.background.as_ref()
54    }
55}
56
57impl GenericNodeInfo for GroupNode {
58    fn id(&self) -> &NodeId {
59        self.generic.id()
60    }
61
62    fn x(&self) -> PixelCoordinate {
63        self.generic.x()
64    }
65
66    fn y(&self) -> PixelCoordinate {
67        self.generic.y()
68    }
69
70    fn width(&self) -> PixelDimension {
71        self.generic.width()
72    }
73
74    fn height(&self) -> PixelDimension {
75        self.generic.height()
76    }
77
78    fn color(&self) -> &Option<Color> {
79        self.generic.color()
80    }
81}
82
83/// The background attributes of a [`GroupNode`].
84#[derive(
85    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
86)]
87#[serde(rename_all = "camelCase")]
88pub struct Background {
89    image: PathBuf,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    background_style: Option<BackgroundStyle>,
92}
93
94impl Background {
95    /// Creates a new [`Background`].
96    #[must_use]
97    pub const fn new(image: PathBuf, background_style: Option<BackgroundStyle>) -> Self {
98        Self {
99            image,
100            background_style,
101        }
102    }
103
104    /// Returns a reference to the image of this [`Background`].
105    #[must_use]
106    pub const fn image(&self) -> &PathBuf {
107        &self.image
108    }
109
110    /// Returns the style of this [`Background`].
111    #[must_use]
112    pub const fn style(&self) -> Option<BackgroundStyle> {
113        self.background_style
114    }
115}
116
117/// The rendering style of the background image.
118#[derive(
119    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
120)]
121#[serde(rename_all = "camelCase")]
122pub enum BackgroundStyle {
123    /// Fills the entire width and height of the node.
124    Cover,
125    /// Maintains the aspect ratio of the background image.
126    Ratio,
127    /// Repeats the image as a pattern in both x/y directions.
128    Repeat,
129}
130