mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-24 10:16:59 -06:00
Merge #764: Swatches: dropping an .ase file on the window loads its swatches
# Conflicts: # ROADMAP.md # crates/ui-egui/src/lib.rs
This commit is contained in:
@@ -128,6 +128,7 @@ list) · [roadmap.md](docs/roadmap.md) (milestones, plan) · [parity-checklist.m
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-10-13** · Dropping an `.ase` file on the window loads its swatches, as Load Swatches does (the drop failed with "Can't Place the File"). No readiness percentage change.
|
||||
- **2026-10-13** · Text takes gradient swatches: a gradient fill or stroke on characters spans the text frame's box (on a path: the path's), on screen and in PDF. No readiness percentage change.
|
||||
- **2026-10-13** · Gradient swatches work on strokes: drawn across the path's box on screen and in PDF (they drew nothing), set with `object.gradient {target: stroke}` and in the Gradient panel when the Stroke box is in front; the stroke's gradient vector moves with the shape and round-trips through IDML. No readiness percentage change.
|
||||
- **2026-10-13** · The Gradient panel follows InDesign's layout (thumbnail, Type, Location, Angle, Reverse, ramp with midpoint diamonds) and takes swatches dragged from the Swatches panel: dropped on a stop they colour it, elsewhere they add a stop. Stops keep their CMYK through panel edits; `object.gradient` stops accept a `swatch`. No readiness percentage change.
|
||||
|
||||
@@ -1237,9 +1237,13 @@ impl DesignApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// A file dropped on the window: documents open, anything else is placed. A file without an
|
||||
/// extension opens when its content is a DesignCraft or IDML document.
|
||||
/// A file dropped on the window: documents open, the swatches in a swatch exchange (.ase) file
|
||||
/// are loaded, and anything else is placed. A file without an extension opens when its content
|
||||
/// is a DesignCraft or IDML document.
|
||||
pub fn open_dropped(&mut self, path: &str) -> Result<Value, String> {
|
||||
if path.to_ascii_lowercase().ends_with(".ase") {
|
||||
return self.run("swatch.load", json!({"path": path}));
|
||||
}
|
||||
let document = opens_as_document(path)
|
||||
|| (std::path::Path::new(path).extension().is_none() && std::fs::read(path).is_ok_and(|b| designcraft_engine::cmd::is_document(&b)));
|
||||
let cmd = if document { "file.open" } else { "file.place" };
|
||||
@@ -2320,6 +2324,28 @@ mod tests {
|
||||
assert!(app.session.documents().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dropping_an_ase_file_loads_its_swatches() {
|
||||
let mut source = Session::new();
|
||||
source.execute("file.new", &json!({})).unwrap();
|
||||
source.execute("swatch.create", &json!({"name": "Dropped Teal", "color": "#108080"})).unwrap();
|
||||
let data = source.execute("swatch.save", &json!({"names": ["Dropped Teal"]})).unwrap();
|
||||
let bytes = designcraft_engine::cmd::base64_decode(data["base64"].as_str().unwrap());
|
||||
for name in ["palette.ase", "PALETTE.ASE"] {
|
||||
let path = std::env::temp_dir().join(format!("designcraft-ui-{}-{name}", std::process::id()));
|
||||
std::fs::write(&path, &bytes).unwrap();
|
||||
let mut app = DesignApp::new(Session::new(), Services::default());
|
||||
app.run("file.new", json!({})).unwrap();
|
||||
let r = app.open_dropped(&path.to_string_lossy());
|
||||
let _ = std::fs::remove_file(&path);
|
||||
assert!(app.ui.dialog.is_none(), "{name}: {:?}", app.ui.dialog.as_ref().map(|d| &d.fields));
|
||||
assert_eq!(r, Ok(json!({"added": 1, "replaced": 0})), "{name}");
|
||||
let doc = &app.session.doc().unwrap().doc;
|
||||
assert!(doc.swatches.iter().any(|s| s.name == "Dropped Teal"), "{name}");
|
||||
assert!(doc.assets.is_empty(), "{name} isn't placed");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_open_failures_show_an_alert() {
|
||||
let path = unreadable_file("open.designcraft");
|
||||
|
||||
Reference in New Issue
Block a user