1use core::iter::DoubleEndedIterator;
2use std::fmt::Display;
3use std::{collections::BTreeMap, fmt::Debug};
4
5use serde::{Deserialize, Serialize};
6
7mod edgestyle;
8mod graphstyle;
9mod nodestyle;
10
11pub use edgestyle::*;
12pub use graphstyle::*;
13pub use nodestyle::*;
14
15#[derive(Clone, Debug, Deserialize, Serialize)]
16#[serde(rename_all = "kebab-case")]
17pub struct Style {
18 background_color: String,
19 background_opacity: f32,
20 fullscreen: bool, edge: EdgeStyle,
22 edge_highlighted: EdgeStyle,
23 graph: GraphStyle,
24 node: NodeStyle,
25 node_highlighted: NodeStyle,
26 subgraph: GraphStyle,
27 utils: StyleUtils,
28}
29impl Style {
30 pub fn from_file(filename: &str) -> Self {
32 let json = std::fs::read_to_string(filename).expect("Error reading json with theme");
33 serde_json::from_str(&json).expect("Error parsing json to Theme")
34 }
35 pub fn dark() -> Self {
37 let json = include_str!("../styles/dark.json");
38 serde_json::from_str(json).expect("Error parsing json to Theme (includstr! dark.json)")
39 }
40 pub fn light() -> Self {
42 let json = include_str!("../styles/light.json");
43 serde_json::from_str(json).expect("Error parsing json to Theme (includstr! light.json)")
44 }
45
46 pub fn get_background_color(&self) -> &str {
48 &self.background_color
49 }
50 pub fn get_background_opacity(&self) -> f32 {
51 self.background_opacity
52 }
53 pub fn get_fullscreen(&self) -> bool {
54 self.fullscreen
55 }
56 pub fn get_edge(&self) -> &EdgeStyle {
57 &self.edge
58 }
59 pub fn get_edge_highlighted(&self) -> &EdgeStyle {
60 &self.edge_highlighted
61 }
62 pub fn get_graph(&self) -> &GraphStyle {
63 &self.graph
64 }
65 pub fn get_node(&self) -> &NodeStyle {
66 &self.node
67 }
68 pub fn get_node_highlighted(&self) -> &NodeStyle {
69 &self.node_highlighted
70 }
71 pub fn get_subgraph(&self) -> &GraphStyle {
72 &self.subgraph
73 }
74 pub fn get_utils(&self) -> &StyleUtils {
75 &self.utils
76 }
77
78 pub fn background_color<S: Display>(mut self, color: S) -> Self {
81 self.background_color = color.to_string();
82 self
83 }
84 pub fn background_opacity(mut self, opacity: f32) -> Self {
85 self.background_opacity = opacity;
86 self
87 }
88 pub fn disable_fullscreen(mut self) -> Self {
90 self.fullscreen = false;
91 self
92 }
93 pub fn def<S: Display>(mut self, def: S) -> Self {
95 self.utils.defs.push(def.to_string());
96 self
97 }
98 pub fn webfont<S: Display>(mut self, font: S) -> Self {
100 self.utils.webfonts.push(font.to_string());
101 self
102 }
103
104 pub fn edge(mut self, configure_edge: impl FnOnce(EdgeStyle) -> EdgeStyle) -> Self {
106 self.edge = configure_edge(self.edge);
107 self
108 }
109 pub fn edge_highlighted(mut self, configure_edge_highlighted: impl FnOnce(EdgeStyle) -> EdgeStyle) -> Self {
110 self.edge_highlighted = configure_edge_highlighted(self.edge_highlighted);
111 self
112 }
113 pub fn graph(mut self, configure_graph: impl FnOnce(GraphStyle) -> GraphStyle) -> Self {
114 self.graph = configure_graph(self.graph);
115 self
116 }
117 pub fn node(mut self, configure_node: impl FnOnce(NodeStyle) -> NodeStyle) -> Self {
118 self.node = configure_node(self.node);
119 self
120 }
121 pub fn node_highlighted(mut self, configure_node_highlighted: impl FnOnce(NodeStyle) -> NodeStyle) -> Self {
122 self.node_highlighted = configure_node_highlighted(self.node_highlighted);
123 self
124 }
125 pub fn subgraph(mut self, configure_subgraph: impl FnOnce(GraphStyle) -> GraphStyle) -> Self {
126 self.subgraph = configure_subgraph(self.subgraph);
127 self
128 }
129}
130impl Default for Style {
131 fn default() -> Self {
132 Self::light()
133 }
134}
135
136#[derive(Clone, Debug, Deserialize, Serialize)]
137#[serde(rename_all = "kebab-case")]
138pub struct StyleUtils {
139 defs: Vec<String>,
140 webfonts: Vec<String>,
141}
142impl StyleUtils {
143 pub fn get_defs(&self) -> &[String] {
146 &self.defs
147 }
148 pub fn get_webfonts(&self) -> &[String] {
150 &self.webfonts
151 }
152}
153
154#[derive(Clone, Debug, Default, Deserialize, Serialize)]
156#[serde(rename_all = "kebab-case")]
157pub struct FontStyle {
158 color: String,
159 family: String,
160 anchor: TextAnchor,
161 opacity: f32,
162 size: f32,
163 attributes: BTreeMap<String, String>,
164}
165impl FontStyle {
166 pub fn get_anchor(&self) -> TextAnchor {
168 self.anchor
169 }
170 pub fn get_color(&self) -> &str {
171 &self.color
172 }
173 pub fn get_family(&self) -> &str {
174 &self.family
175 }
176 pub fn get_opacity(&self) -> f32 {
177 self.opacity
178 }
179 pub fn get_size(&self) -> f32 {
180 self.size
181 }
182 pub fn attrs(&self) -> impl DoubleEndedIterator<Item = (&String, &String)> {
183 self.attributes.iter()
184 }
185
186 pub fn anchor(mut self, anchor: TextAnchor) -> Self {
188 self.anchor = anchor;
189 self
190 }
191 pub fn color<S: Display>(mut self, color: S) -> Self {
192 self.color = color.to_string();
193 self
194 }
195 pub fn family<S: Display>(mut self, family: S) -> Self {
196 self.family = family.to_string();
197 self
198 }
199 pub fn opacity<I: Into<f64>>(mut self, new_opacity: I) -> Self {
200 self.opacity = new_opacity.into() as f32;
201 self
202 }
203 pub fn size<I: Into<f64>>(mut self, new_size: I) -> Self {
204 self.size = new_size.into() as f32;
205 self
206 }
207 pub fn set<K: Display, V: Display>(mut self, attr: K, value: V) -> Self {
209 self.attributes.insert(attr.to_string(), value.to_string());
210 self
211 }
212}
213
214#[derive(Clone, Debug, Default, Deserialize, Serialize)]
215#[serde(rename_all = "kebab-case")]
216pub struct FrameStyle {
217 enabled: bool,
218 color: String,
219 opacity: f32,
220 thickness: f32,
221 attributes: BTreeMap<String, String>,
222}
223impl FrameStyle {
224 pub fn enabled(&self) -> bool {
226 self.enabled
227 }
228 pub fn get_color(&self) -> &str {
229 &self.color
230 }
231 pub fn get_opacity(&self) -> f32 {
232 self.opacity
233 }
234 pub fn get_thickness(&self) -> f32 {
235 self.thickness
236 }
237 pub fn attrs(&self) -> impl DoubleEndedIterator<Item = (&String, &String)> {
238 self.attributes.iter()
239 }
240
241 pub fn disable(mut self) -> Self {
243 self.enabled = false;
244 self
245 }
246 pub fn enable(mut self) -> Self {
247 self.enabled = true;
248 self
249 }
250 pub fn color<S: Display>(mut self, color: S) -> Self {
251 self.color = color.to_string();
252 self
253 }
254 pub fn opacity<I: Into<f64>>(mut self, new_opacity: I) -> Self {
255 self.opacity = new_opacity.into() as f32;
256 self
257 }
258 pub fn thickness<I: Into<f64>>(mut self, new_thickness: I) -> Self {
259 self.thickness = new_thickness.into() as f32;
260 self
261 }
262 pub fn set<K: Display, V: Display>(mut self, attr: K, value: V) -> Self {
264 self.attributes.insert(attr.to_string(), value.to_string());
265 self
266 }
267}
268
269#[derive(Clone, Debug, Deserialize, Serialize)]
270#[serde(rename_all = "kebab-case")]
271pub struct LineStyle {
272 arrowsize: f32,
273 color: String,
274 opacity: f32,
275 thickness: f32,
276 attributes: BTreeMap<String, String>,
277}
278impl LineStyle {
279 pub fn get_arrowsize(&self) -> f32 {
281 self.arrowsize
282 }
283 pub fn get_color(&self) -> &str {
284 &self.color
285 }
286 pub fn get_opacity(&self) -> f32 {
287 self.opacity
288 }
289 pub fn get_thickness(&self) -> f32 {
290 self.thickness
291 }
292 pub fn attrs(&self) -> impl DoubleEndedIterator<Item = (&String, &String)> {
293 self.attributes.iter()
294 }
295
296 pub fn arrowsize<I: Into<f64>>(mut self, new_arrowsize: I) -> Self {
298 self.arrowsize = new_arrowsize.into() as f32;
299 self
300 }
301 pub fn color<S: Display>(mut self, color: S) -> Self {
302 self.color = color.to_string();
303 self
304 }
305 pub fn opacity<I: Into<f64>>(mut self, new_opacity: I) -> Self {
306 self.opacity = new_opacity.into() as f32;
307 self
308 }
309 pub fn thickness<I: Into<f64>>(mut self, new_thickness: I) -> Self {
310 self.thickness = new_thickness.into() as f32;
311 self
312 }
313 pub fn set<K: Display, V: Display>(mut self, attr: K, value: V) -> Self {
315 self.attributes.insert(attr.to_string(), value.to_string());
316 self
317 }
318}
319
320#[derive(Copy, Clone, Default, Deserialize, Serialize)]
321#[serde(rename_all = "kebab-case")]
322pub enum TextAnchor {
323 #[default]
324 Start,
325 Middle,
326 End,
327}
328impl Debug for TextAnchor {
329 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
330 let anchor = match self {
331 Self::Start => "start",
332 Self::Middle => "middle",
333 Self::End => "end",
334 };
335 write!(f, "{anchor}")
336 }
337}
338
339pub trait RectStyling {
341 fn get_background_color(&self) -> &str;
343 fn get_background_opacity(&self) -> f32;
344 fn get_border_radius(&self) -> f32;
345 fn get_padding(&self) -> f32;
346 fn get_margin(&self) -> f32;
347 fn get_height(&self) -> Option<f32>;
348 fn get_width(&self) -> Option<f32>;
349
350 fn background_color<S: Display>(self, color: S) -> Self;
352 fn background_opacity<I: Into<f64>>(self, opacity: I) -> Self;
353 fn border_radius<I: Into<f64>>(self, radius: I) -> Self;
354 fn padding<I: Into<f64>>(self, padding: I) -> Self;
355 fn margin<I: Into<f64>>(self, margin: I) -> Self;
356 fn height<I: Into<f64>>(self, height: I) -> Self;
358 fn width<I: Into<f64>>(self, width: I) -> Self;
360}