M3.7: neutral paint, effect and stroke labels

The wide-gamut RGB working space is now "Wide Gamut RGB (1998 primaries)";
its old name still resolves everywhere (cms::profile / canonical_name,
Color Settings, Assign Profile, documents and settings saved earlier).
The Effect menu section is "Vector Effects", stroke width profiles are
Lens / Taper Start / Taper End, dash, arrowhead-tip and gradient-on-stroke
tooltips are reworded, the Window library submenus hold neutral disabled
placeholders until the generated libraries land, and the Swatches menu
offers "Save Swatch Library…" (disabled).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-04 11:17:50 +07:00
co-authored by Claude Opus 5.5
parent d99853ed2a
commit 016fcbf34e
11 changed files with 169 additions and 45 deletions
+7 -8
View File
@@ -157,10 +157,10 @@ fn color_settings(s: &mut Session, p: &Value) -> Result<Value> {
let mut st = cms::active_settings();
let before = st.clone();
if let Some(v) = str_param(p, "rgb") {
st.rgb = v.to_string();
st.rgb = cms::canonical_name(v).to_string();
}
if let Some(v) = str_param(p, "cmyk") {
st.cmyk = v.to_string();
st.cmyk = cms::canonical_name(v).to_string();
}
if let Some(i) = intent_param(p, C)? {
st.intent = i;
@@ -189,24 +189,23 @@ fn load_profile(_: &mut Session, _: &Value) -> Result<Value> {
/// The document's assigned profiles (`None` = working space).
pub fn doc_profiles(d: &vectorcraft_doc::Document) -> (Option<String>, Option<String>) {
let o = d.unknown.get(PROFILES_KEY);
let get = |k: &str| o.and_then(|o| o.get(k)).and_then(Value::as_str).map(str::to_string);
let get = |k: &str| o.and_then(|o| o.get(k)).and_then(Value::as_str).map(|n| cms::canonical_name(n).to_string());
(get("rgb"), get("cmyk"))
}
fn assign_profile(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "edit.assignProfile";
let (mut rgb, mut cmyk) = doc_profiles(&s.doc()?.doc);
let known = cms::profiles();
let pick = |key: &str, cur: &mut Option<String>, kind: cms::ProfileKind| -> Result<bool> {
match p.get(key) {
None => Ok(false),
Some(Value::Null) => Ok(cur.take().is_some()),
Some(Value::String(n)) => {
if !known.iter().any(|k| &k.name == n && k.kind == kind) {
let Some(info) = cms::profile(n).filter(|k| k.kind == kind) else {
return Err(bad(C, format!("unknown {key} profile `{n}`")));
}
let changed = cur.as_deref() != Some(n.as_str());
*cur = Some(n.clone());
};
let changed = cur.as_deref() != Some(info.name.as_str());
*cur = Some(info.name);
Ok(changed)
}
Some(_) => Err(bad(C, format!("`{key}` must be a profile name or null"))),
+21
View File
@@ -377,3 +377,24 @@ fn intents_reach_the_document_conversion() {
assert_ne!(first(&a), first(&b));
let _ = Intent::Perceptual;
}
#[test]
fn legacy_profile_name_resolves_in_commands_and_files() {
const OLD: &str = "Adobe RGB (1998) compatible"; // brand-ok: legacy alias under test
let _g = GLOBAL.lock().unwrap_or_else(|e| e.into_inner());
let mut s = session();
let before = cms::active_settings();
let r = s.execute("edit.colorSettings", &json!({"rgb": OLD})).unwrap();
assert_eq!(r["rgb"], cms::WIDE_GAMUT_RGB);
assert_eq!(cms::active_settings().rgb, cms::WIDE_GAMUT_RGB);
let names: Vec<&str> = r["profiles"].as_array().unwrap().iter().map(|p| p["name"].as_str().unwrap()).collect();
assert!(names.contains(&cms::WIDE_GAMUT_RGB) && !names.contains(&OLD));
let r = s.execute("edit.assignProfile", &json!({"rgb": OLD})).unwrap();
assert_eq!(r["rgb"], cms::WIDE_GAMUT_RGB, "stored under the current name");
// A document saved by an older version names the profile the old way.
let mut d = (*s.doc().unwrap().doc).clone();
d.unknown.insert(cmd::colormgmt::PROFILES_KEY.into(), json!({"rgb": OLD, "cmyk": null}));
let back = vectorcraft_format::load(&vectorcraft_format::save(&d, false)).unwrap();
assert_eq!(cmd::colormgmt::doc_profiles(&back), (Some(cms::WIDE_GAMUT_RGB.to_string()), None));
cms::set_active(&before).unwrap();
}