mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 07:10:13 +00:00
SVG Options: Show Code under Export Selection shows the selection
Show Code in the SVG Options dialog that File > Export Selection opens encoded the whole document at the first artboard, while OK writes the selected objects alone, cropped to them. The code view now encodes the same selection document OK writes, without the artboard options, and encodes it again when the selection changes.
This commit is contained in:
@@ -269,30 +269,45 @@ fn artboards(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
});
|
||||
}
|
||||
|
||||
/// The SVG the current options write for the first chosen artboard (read-only, selectable),
|
||||
/// encoded again only when the options or the document change.
|
||||
/// The SVG the current options write for the first chosen artboard, or under Export Selection for
|
||||
/// the selection alone, cropped to it (read-only, selectable), encoded again only when the
|
||||
/// options, the document or the selection change.
|
||||
fn code_view(app: &VectorcraftApp, ui: &mut egui::Ui, d: &Dialog) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let Some(st) = app.session.active() else { return };
|
||||
let selection = d.bool(super::export_as::SELECTION_FIELD);
|
||||
let mut opts = options(d);
|
||||
if let Some(o) = opts.as_object_mut()
|
||||
&& let Some(r) = o.remove("range")
|
||||
{
|
||||
// The first artboard of the range (or the first one).
|
||||
let first = r.as_str().and_then(|r| r.split([',', '-', '\u{2013}']).next()).and_then(|n| n.trim().parse::<usize>().ok());
|
||||
o.insert("artboard".into(), json!(first.map_or(0, |n| n.saturating_sub(1))));
|
||||
if let Some(o) = opts.as_object_mut() {
|
||||
if selection {
|
||||
// Export Selection writes one crop, without artboards to choose.
|
||||
for k in vectorcraft_engine::cmd::fileio::ARTBOARD_PARAMS.iter().chain(&["useArtboards"]) {
|
||||
o.remove(*k);
|
||||
}
|
||||
} else if let Some(r) = o.remove("range") {
|
||||
// The first artboard of the range (or the first one).
|
||||
let first = r.as_str().and_then(|r| r.split([',', '-', '\u{2013}']).next()).and_then(|n| n.trim().parse::<usize>().ok());
|
||||
o.insert("artboard".into(), json!(first.map_or(0, |n| n.saturating_sub(1))));
|
||||
}
|
||||
}
|
||||
// One cached text, replaced when the document or the options change.
|
||||
// One cached text, replaced when the document, the options or the selection change.
|
||||
let key = egui::Id::unique("svg-code");
|
||||
// The read roots in force and the document's folder decide whether the text may be shown.
|
||||
let roots = vectorcraft_engine::file_access::current().map(|r| r.describe());
|
||||
let sig = egui::Id::unique((st.uid, st.revision, opts.to_string(), roots, st.path.as_deref())).value();
|
||||
let selected = selection.then(|| st.selection.objects.clone());
|
||||
let sig = egui::Id::unique((st.uid, st.revision, opts.to_string(), roots, st.path.as_deref(), selected)).value();
|
||||
let code: Arc<String> = match ui.ctx().data(|m| m.get_temp::<(u64, Arc<String>)>(key)).filter(|(s, _)| *s == sig) {
|
||||
Some((_, c)) => c,
|
||||
None => {
|
||||
const MAX: usize = 200_000;
|
||||
let encoded = vectorcraft_engine::cmd::fileio::check_linked_scripts("document.export", "svg", st)
|
||||
.and_then(|()| vectorcraft_engine::cmd::fileio::encode_all(&st.doc, "svg", &json!({ "svg": opts })));
|
||||
let encoded = vectorcraft_engine::cmd::fileio::check_linked_scripts("document.export", "svg", st).and_then(|()| {
|
||||
let params = json!({ "svg": opts });
|
||||
if selection {
|
||||
let (doc, _) = vectorcraft_engine::cmd::fileio::selection_doc(st, "document.exportSelection", false)?;
|
||||
vectorcraft_engine::cmd::fileio::encode_all(&doc, "svg", ¶ms)
|
||||
} else {
|
||||
vectorcraft_engine::cmd::fileio::encode_all(&st.doc, "svg", ¶ms)
|
||||
}
|
||||
});
|
||||
let mut text = match encoded {
|
||||
// Shown as text whatever the file's encoding.
|
||||
Ok(enc) => enc
|
||||
@@ -431,6 +446,37 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(root);
|
||||
}
|
||||
|
||||
/// Show Code under Export Selection shows the SVG that OK writes: the selection alone, cropped
|
||||
/// to it with what its effects draw, not the whole document.
|
||||
#[test]
|
||||
fn show_code_under_export_selection_shows_the_selection() {
|
||||
let (mut app, written) = app("/tmp/selection.svg");
|
||||
app.run("shape.rectangle", json!({"x": 70, "y": 40, "width": 20, "height": 20})).unwrap();
|
||||
app.run("effect.apply", json!({"effect": "stylize.dropShadow"})).unwrap();
|
||||
app.run("document.exportSelection", Value::Null).unwrap();
|
||||
let d = app.ui.dialog.as_mut().expect("SVG Options opened");
|
||||
assert_eq!(d.kind, KIND);
|
||||
assert!(d.bool(super::super::export_as::SELECTION_FIELD));
|
||||
d.fields.insert("showCode".into(), json!(true));
|
||||
// The text the code view shows after two frames in one context.
|
||||
let ctx = egui::Context::default();
|
||||
theme::install_fonts(&ctx);
|
||||
for _ in 0..2 {
|
||||
let mut out = ctx.run_ui(Default::default(), |ui| super::super::show(&mut app, ui.ctx()));
|
||||
out.textures_delta.clear();
|
||||
}
|
||||
let code = ctx.data(|m| m.get_temp::<(u64, Arc<String>)>(egui::Id::unique("svg-code"))).map(|(_, c)| c.to_string()).unwrap_or_default();
|
||||
super::super::confirm(&mut app).unwrap();
|
||||
let svg = text(&written, 0);
|
||||
assert_eq!(written.borrow()[0].0, "/tmp/selection.svg");
|
||||
assert_eq!(code, svg, "Show Code shows what OK writes");
|
||||
// The shadow reaches past the 21-point square, and the other rectangle is left out.
|
||||
assert!(!svg.contains("viewBox=\"0 0 120 80\"") && !svg.contains("viewBox=\"0 0 21 21\""), "{svg}");
|
||||
assert!(!svg.contains("width=\"40\""), "{svg}");
|
||||
assert_eq!(svg.matches("<rect").count(), 1, "{svg}");
|
||||
assert!(svg.contains("width=\"20\" height=\"20\"") && svg.contains("<feOffset"), "{svg}");
|
||||
}
|
||||
|
||||
/// A dialog a save panel opened carries the dialog layer's own `__` fields; the save is given
|
||||
/// only the SVG options, so it is not refused for an unknown key.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user