M3.27: Color Picker reads colours with the engine's color_value (one parser; CMYK and grey in percent as the paint commands take them) instead of its own copy

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-04 18:24:22 +07:00
parent c071dcd4d0
commit ad82e6e9a9
3 changed files with 10 additions and 18 deletions

View File

@ -240,7 +240,7 @@ pub fn matrix_param(p: &Value, key: &str) -> Option<Affine> {
Some(Affine::new(c))
}
/// A colour from `"#rrggbb"`, `[r,g,b]` (0..1), `{"c":..,"m":..,"y":..,"k":..}` or `{"gray":..}`.
pub(crate) fn color_value(v: &Value) -> Option<Color> {
pub fn color_value(v: &Value) -> Option<Color> {
match v {
Value::String(s) => Color::from_hex(s),
Value::Array(a) if a.len() >= 3 => Some(Color::rgb(a[0].as_f64()? as f32, a[1].as_f64()? as f32, a[2].as_f64()? as f32)),

View File

@ -12,10 +12,11 @@ use serde_json::{Value, json};
use vectorcraft_color::cms::{self, Lab};
use vectorcraft_color::{Color, Paint};
use vectorcraft_doc::ColorMode;
use vectorcraft_engine::cmd::color_value;
use super::DialogSpec;
use crate::panels::color::{GAMUT_WARNING, WEB_WARNING, gamut_fix, hex_digits, is_web_safe, parse_hex, warning_chip, web_safe};
use crate::panels::{c32, color_from_json, color_json};
use crate::panels::{c32, color_json};
use crate::state::Dialog;
use crate::theme::Tokens;
use crate::{VectorcraftApp, widgets};
@ -132,7 +133,7 @@ fn picked(d: &Dialog) -> Picked {
let hex = d.str("hex");
let color = match parse_hex(&hex) {
Some(c) if hex != d.str("__hex") => c,
_ => d.fields.get("color").and_then(color_from_json).unwrap_or(Color::WHITE),
_ => d.fields.get("color").and_then(color_value).unwrap_or(Color::WHITE),
};
let hsb = d.fields.get("__hsb").and_then(|v| serde_json::from_value::<[f32; 3]>(v.clone()).ok());
let p = match hsb {
@ -165,7 +166,7 @@ fn proxy_color(app: &VectorcraftApp, stroke: bool) -> Color {
pub fn open(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
let stroke = p.get("stroke").and_then(Value::as_bool).unwrap_or(!app.session.fill_active);
let color = match p.get("color") {
Some(v) => color_from_json(v).ok_or_else(|| format!("bad color {v}"))?,
Some(v) => color_value(v).ok_or_else(|| format!("bad color {v}"))?,
None => proxy_color(app, stroke),
};
let mut d = Dialog::new(
@ -182,7 +183,7 @@ fn body(app: &mut VectorcraftApp, ui: &mut Ui, d: &mut Dialog) -> bool {
let web = d.bool("webOnly");
let swatches = d.bool("swatches");
let p = picked(d);
let original = d.fields.get("original").and_then(color_from_json).unwrap_or(p.color);
let original = d.fields.get("original").and_then(color_value).unwrap_or(p.color);
let gamut = gamut_fix(app, ui.ctx(), "picker-gamut", &p.color);
let mut pick: Option<Picked> = None;
let mut new_channel = None;
@ -481,6 +482,10 @@ mod tests {
super::super::confirm(&mut app).unwrap();
assert!(matches!(crate::panels::current_paints(&app).0.color(), Some(Color::Cmyk { .. })), "CMYK is kept");
assert!(app.run("ui.colorPicker", json!({"color": "nope"})).is_err());
// Colours take every form the paint commands take (CMYK in percent too).
app.run("ui.colorPicker", json!({"stroke": false, "color": {"c": 0, "m": 100, "y": 100, "k": 0}})).unwrap();
super::super::confirm(&mut app).unwrap();
assert_eq!(crate::panels::current_paints(&app).0.color(), Some(Color::cmyk(0.0, 1.0, 1.0, 0.0)));
}
#[test]

View File

@ -282,19 +282,6 @@ pub(crate) fn recent_colors_row(app: &mut VectorcraftApp, ui: &mut Ui) {
}
}
/// A colour from command JSON: `"#rrggbb"`, `[r,g,b]`, `{c,m,y,k}`, `{gray}` (inverse of
/// [`color_json`]) or a serialized colour.
pub(crate) fn color_from_json(v: &Value) -> Option<Color> {
let f = |v: Option<&Value>| v.and_then(Value::as_f64).map(|x| x as f32);
match v {
Value::String(s) => color::parse_hex(s),
Value::Array(a) if a.len() == 3 => Some(Color::rgb(f(a.first())?, f(a.get(1))?, f(a.get(2))?)),
Value::Object(o) if o.contains_key("gray") => Some(Color::gray(f(o.get("gray"))?)),
Value::Object(o) if !o.contains_key("model") => Some(Color::cmyk(f(o.get("c"))?, f(o.get("m"))?, f(o.get("y"))?, f(o.get("k"))?)),
_ => serde_json::from_value(v.clone()).ok(),
}
}
/// A colour as command JSON, keeping its model.
pub(crate) fn color_json(c: &Color) -> Value {
match *c {