Fixed bugs for svg
This commit is contained in:
@ -75,9 +75,9 @@ pub enum BasicDataType {
|
|||||||
derive(serde::Serialize, serde::Deserialize)
|
derive(serde::Serialize, serde::Deserialize)
|
||||||
)]
|
)]
|
||||||
pub enum BasicValue {
|
pub enum BasicValue {
|
||||||
SaveString {
|
SaveBytes {
|
||||||
path: String,
|
path: String,
|
||||||
value: String,
|
value: Vec<u8>,
|
||||||
},
|
},
|
||||||
Error {
|
Error {
|
||||||
value: LayoutJob,
|
value: LayoutJob,
|
||||||
@ -225,7 +225,7 @@ impl Hash for BasicValue {
|
|||||||
);
|
);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
| Self::SaveString { path, value } => {
|
| Self::SaveBytes { path, value } => {
|
||||||
path.hash(state);
|
path.hash(state);
|
||||||
value.hash(state);
|
value.hash(state);
|
||||||
},
|
},
|
||||||
@ -284,6 +284,7 @@ pub enum NodeInstruction {
|
|||||||
ColorNode,
|
ColorNode,
|
||||||
ColorEdge,
|
ColorEdge,
|
||||||
StringToSvg,
|
StringToSvg,
|
||||||
|
SaveSvg,
|
||||||
|
|
||||||
// convert basic data types
|
// convert basic data types
|
||||||
ToPositiveSet,
|
ToPositiveSet,
|
||||||
@ -493,6 +494,7 @@ impl NodeInstruction {
|
|||||||
],
|
],
|
||||||
| Self::Sleep => vec![("seconds", PositiveInt)],
|
| Self::Sleep => vec![("seconds", PositiveInt)],
|
||||||
| Self::StringToSvg => vec![("value", String)],
|
| Self::StringToSvg => vec![("value", String)],
|
||||||
|
| Self::SaveSvg => vec![("path", Path), ("value", Svg)]
|
||||||
}
|
}
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| (e.0.to_string(), e.1))
|
.map(|e| (e.0.to_string(), e.1))
|
||||||
@ -589,6 +591,7 @@ impl NodeInstruction {
|
|||||||
| Self::PositiveBisimilarityPaigeTarjan => vec![("out", String)],
|
| Self::PositiveBisimilarityPaigeTarjan => vec![("out", String)],
|
||||||
| Self::Sleep => vec![("out", PositiveInt)],
|
| Self::Sleep => vec![("out", PositiveInt)],
|
||||||
| Self::StringToSvg => vec![("out", Svg)],
|
| Self::StringToSvg => vec![("out", Svg)],
|
||||||
|
| Self::SaveSvg => vec![],
|
||||||
};
|
};
|
||||||
res.into_iter()
|
res.into_iter()
|
||||||
.map(|res| (res.0.to_string(), res.1))
|
.map(|res| (res.0.to_string(), res.1))
|
||||||
@ -1087,6 +1090,7 @@ impl NodeTemplateTrait for NodeInstruction {
|
|||||||
"Positive Paige & Torjan",
|
"Positive Paige & Torjan",
|
||||||
| Self::Sleep => "Sleep",
|
| Self::Sleep => "Sleep",
|
||||||
| Self::StringToSvg => "String to SVG",
|
| Self::StringToSvg => "String to SVG",
|
||||||
|
| Self::SaveSvg => "Save SVG",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1169,7 +1173,8 @@ impl NodeTemplateTrait for NodeInstruction {
|
|||||||
| Self::PositiveBisimilarityPaigeTarjan =>
|
| Self::PositiveBisimilarityPaigeTarjan =>
|
||||||
vec!["Positive Graph", "Positive Bisimilarity"],
|
vec!["Positive Graph", "Positive Bisimilarity"],
|
||||||
| Self::Sleep
|
| Self::Sleep
|
||||||
| Self::StringToSvg => vec!["General"],
|
| Self::StringToSvg
|
||||||
|
| Self::SaveSvg => vec!["General"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1276,6 +1281,7 @@ impl NodeTemplateIter for AllInstructions {
|
|||||||
NodeInstruction::PositiveBisimilarityPaigeTarjan,
|
NodeInstruction::PositiveBisimilarityPaigeTarjan,
|
||||||
NodeInstruction::Sleep,
|
NodeInstruction::Sleep,
|
||||||
NodeInstruction::StringToSvg,
|
NodeInstruction::StringToSvg,
|
||||||
|
NodeInstruction::SaveSvg,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1298,7 +1304,7 @@ impl WidgetValueTrait for BasicValue {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
// Dummy values used to save files, no ui since not needed
|
// Dummy values used to save files, no ui since not needed
|
||||||
| BasicValue::SaveString { path: _, value: _ } => {},
|
| BasicValue::SaveBytes { path: _, value: _ } => {},
|
||||||
| BasicValue::Error { value: _ } => {},
|
| BasicValue::Error { value: _ } => {},
|
||||||
|
|
||||||
| BasicValue::String { value } => {
|
| BasicValue::String { value } => {
|
||||||
@ -1461,6 +1467,13 @@ impl NodeDataTrait for NodeData {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
| (_, NodeInstruction::SaveSvg) => {
|
||||||
|
if ui.button("Write").clicked() {
|
||||||
|
responses.push(NodeResponse::User(
|
||||||
|
CustomResponse::SaveToFile(node_id),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
| (true, NodeInstruction::ReadPath) => {
|
| (true, NodeInstruction::ReadPath) => {
|
||||||
// since no filewatcher we simply give the option to reload the
|
// since no filewatcher we simply give the option to reload the
|
||||||
// file
|
// file
|
||||||
@ -1936,7 +1949,7 @@ impl eframe::App for AppHandle {
|
|||||||
let text = get_layout(Err(e), &self.translator.lock().unwrap(), ctx);
|
let text = get_layout(Err(e), &self.translator.lock().unwrap(), ctx);
|
||||||
self.cached_last_value = Some(text);
|
self.cached_last_value = Some(text);
|
||||||
} else if let Some(l_b_v) = self.cache.get_last_state() {
|
} else if let Some(l_b_v) = self.cache.get_last_state() {
|
||||||
if let BasicValue::SaveString { path, value } = &l_b_v {
|
if let BasicValue::SaveBytes { path, value } = &l_b_v {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let mut f = match std::fs::File::create(path) {
|
let mut f = match std::fs::File::create(path) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
@ -1945,7 +1958,7 @@ impl eframe::App for AppHandle {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(e) = write!(f, "{}", value) {
|
if let Err(e) = f.write_all(value) {
|
||||||
println!("Error writing to file {path}: {e}");
|
println!("Error writing to file {path}: {e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1970,7 +1983,7 @@ impl eframe::App for AppHandle {
|
|||||||
let text = get_layout(Err(e), &self.translator.lock().unwrap(), ctx);
|
let text = get_layout(Err(e), &self.translator.lock().unwrap(), ctx);
|
||||||
self.cached_last_value = Some(content.clone());
|
self.cached_last_value = Some(content.clone());
|
||||||
} else if let Some(l_b_v) = self.cache.get_last_state() {
|
} else if let Some(l_b_v) = self.cache.get_last_state() {
|
||||||
if let BasicValue::SaveString { path, value } = &l_b_v {
|
if let BasicValue::SaveBytes { path, value } = &l_b_v {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let mut f = match std::fs::File::create(path) {
|
let mut f = match std::fs::File::create(path) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
@ -2103,7 +2116,7 @@ fn get_layout(
|
|||||||
|
|
||||||
match value {
|
match value {
|
||||||
| Ok(value) => match value {
|
| Ok(value) => match value {
|
||||||
| BasicValue::SaveString { path, value: _ } => text.append(
|
| BasicValue::SaveBytes { path, value: _ } => text.append(
|
||||||
&format!("Saving to file \"{}\"", path),
|
&format!("Saving to file \"{}\"", path),
|
||||||
0., Default::default(),
|
0., Default::default(),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -108,11 +108,14 @@ fn generate_to_evaluate(
|
|||||||
for n_id in dependencies {
|
for n_id in dependencies {
|
||||||
let mut input_hashes = vec![];
|
let mut input_hashes = vec![];
|
||||||
|
|
||||||
if let NodeInstruction::SaveString = graph[n_id].user_data.template {
|
match graph[n_id].user_data.template {
|
||||||
res.push(n_id);
|
NodeInstruction::SaveString | NodeInstruction::SaveSvg => {
|
||||||
invalid_ids.insert(n_id);
|
res.push(n_id);
|
||||||
outputs_cache.invalidate_outputs(graph, n_id);
|
invalid_ids.insert(n_id);
|
||||||
continue;
|
outputs_cache.invalidate_outputs(graph, n_id);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let first_output =
|
let first_output =
|
||||||
@ -848,7 +851,7 @@ fn process_template(
|
|||||||
BasicValue::Path { value: path },
|
BasicValue::Path { value: path },
|
||||||
BasicValue::String { value },
|
BasicValue::String { value },
|
||||||
) => {
|
) => {
|
||||||
*to_ret = Some(BasicValue::SaveString { path, value });
|
*to_ret = Some(BasicValue::SaveBytes { path, value: value.into() });
|
||||||
},
|
},
|
||||||
| (BasicValue::Path { .. }, _) => {
|
| (BasicValue::Path { .. }, _) => {
|
||||||
anyhow::bail!("Not a string");
|
anyhow::bail!("Not a string");
|
||||||
@ -2513,6 +2516,36 @@ fn process_template(
|
|||||||
anyhow::bail!("Not a string");
|
anyhow::bail!("Not a string");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
| NodeInstruction::SaveSvg => {
|
||||||
|
let (path, svg) = retrieve_from_cache![2];
|
||||||
|
|
||||||
|
match (path, svg) {
|
||||||
|
| (
|
||||||
|
BasicValue::Path { value: path },
|
||||||
|
BasicValue::Svg { value },
|
||||||
|
) => {
|
||||||
|
let mut path = path.to_string();
|
||||||
|
if !path.ends_with(".png") {
|
||||||
|
path.push_str(".png");
|
||||||
|
}
|
||||||
|
let svg = match value.rasterize() {
|
||||||
|
Ok(svg) => svg,
|
||||||
|
Err(e) => anyhow::bail!(e),
|
||||||
|
};
|
||||||
|
let raw = svg.into_raw();
|
||||||
|
*to_ret = Some(BasicValue::SaveBytes { path, value: raw });
|
||||||
|
},
|
||||||
|
| (BasicValue::Path { .. }, _) => {
|
||||||
|
anyhow::bail!("Not an svg");
|
||||||
|
},
|
||||||
|
| (_, BasicValue::Svg { .. }) => {
|
||||||
|
anyhow::bail!("Not a path");
|
||||||
|
},
|
||||||
|
| (_, _) => {
|
||||||
|
anyhow::bail!("Values of wrong type");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#![forbid(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![warn(clippy::all, rust_2018_idioms)]
|
#![warn(clippy::all, rust_2018_idioms)]
|
||||||
// Forbid warnings in release builds
|
// Forbid warnings in release builds
|
||||||
#![cfg_attr(not(debug_assertions), deny(warnings))]
|
#![cfg_attr(not(debug_assertions), deny(warnings))]
|
||||||
|
|||||||
@ -13,6 +13,8 @@ pub(crate) struct Svg {
|
|||||||
/// original size of the svg
|
/// original size of the svg
|
||||||
svg_size: egui::Vec2,
|
svg_size: egui::Vec2,
|
||||||
|
|
||||||
|
original: String,
|
||||||
|
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
svg_texture: Arc<Mutex<Option<egui::TextureHandle>>>,
|
svg_texture: Arc<Mutex<Option<egui::TextureHandle>>>,
|
||||||
}
|
}
|
||||||
@ -53,7 +55,10 @@ impl Svg {
|
|||||||
|
|
||||||
let image = egui::ColorImage::from_rgba_unmultiplied([w as _, h as _], &data);
|
let image = egui::ColorImage::from_rgba_unmultiplied([w as _, h as _], &data);
|
||||||
|
|
||||||
let svg = Svg { image, svg_size, svg_texture: Arc::new(Mutex::new(None)) };
|
let svg = Svg { image,
|
||||||
|
original: content,
|
||||||
|
svg_size,
|
||||||
|
svg_texture: Arc::new(Mutex::new(None)) };
|
||||||
|
|
||||||
Ok(svg)
|
Ok(svg)
|
||||||
}
|
}
|
||||||
@ -69,6 +74,19 @@ impl Svg {
|
|||||||
svg_texture
|
svg_texture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rasterize(&self) -> Result<nsvg::image::ImageBuffer<nsvg::image::Rgba<u8>, Vec<u8>>, String> {
|
||||||
|
let svg = match nsvg::parse_str(&self.original, nsvg::Units::Pixel, 96.0) {
|
||||||
|
Ok(svg) => svg,
|
||||||
|
Err(nsvg_err) => return Err(format!("{}", nsvg_err)),
|
||||||
|
};
|
||||||
|
let data = match svg.rasterize(1.) {
|
||||||
|
Ok(o) => o,
|
||||||
|
Err(e) => return Err(format!("{}", e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Svg {
|
impl Debug for Svg {
|
||||||
@ -105,6 +123,7 @@ impl Hash for Svg {
|
|||||||
hash_float!(self.svg_size.y);
|
hash_float!(self.svg_size.y);
|
||||||
self.image.pixels.hash(state);
|
self.image.pixels.hash(state);
|
||||||
self.image.size.hash(state);
|
self.image.size.hash(state);
|
||||||
|
self.original.hash(state);
|
||||||
hash_float!(self.image.source_size.x);
|
hash_float!(self.image.source_size.x);
|
||||||
hash_float!(self.image.source_size.y);
|
hash_float!(self.image.source_size.y);
|
||||||
self.svg_texture.lock().expect("Poisoned").hash(state);
|
self.svg_texture.lock().expect("Poisoned").hash(state);
|
||||||
|
|||||||
Reference in New Issue
Block a user