mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 17:56:50 -06:00
Merge pull request #2617 from dotCooCoo/fix/effect-color-param-refuses-unreadable
Effects: effect.apply and effect.setParams refuse a color the effect can't draw
This commit is contained in:
@@ -138,6 +138,7 @@ pub(crate) fn apply(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if !params.is_null() && !params.is_object() {
|
||||
return Err(bad(C, "`params` must be an object"));
|
||||
}
|
||||
super::params::check_effect_color(C, id, ¶ms)?;
|
||||
// Crop Marks take their style from the preferences when applied.
|
||||
if id == effects::CROP_MARKS && params.get("style").is_none() {
|
||||
params["style"] = json!(s.crop_mark_style().id());
|
||||
@@ -313,7 +314,11 @@ fn set_params(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
.transpose()?;
|
||||
let visible = p.get("visible").and_then(Value::as_bool);
|
||||
let item = item_target(s, p, C)?;
|
||||
if set_params_effects(s, p).iter().any(|e| e == GLASS) {
|
||||
let edited = set_params_effects(s, p);
|
||||
for effect in &edited {
|
||||
super::params::check_effect_color(C, effect, ¶ms)?;
|
||||
}
|
||||
if edited.iter().any(|e| e == GLASS) {
|
||||
load_texture(&mut params, C)?;
|
||||
}
|
||||
for id in appearance_targets(s, p)? {
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
//! command with its default. So are the `params` of an effect (#1592): `effect.apply` and
|
||||
//! `effect.setParams` answer a key the effect doesn't take, or a value of another type than its
|
||||
//! default, with a parameter error ([`check_effect_params`]). [`Session::execute`] itself takes
|
||||
//! what it is given, so the journal of an older version still replays.
|
||||
//! what it is given, so the journal of an older version still replays, except for an effect's
|
||||
//! `color` that the effect can't read, which `effect.apply` and `effect.setParams` refuse
|
||||
//! themselves ([`check_effect_color`]).
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -212,8 +214,9 @@ fn unknown(id: &str, key: &str, keys: &[&str]) -> crate::EngineError {
|
||||
|
||||
/// `params` of built-in effect `effect`, as command `id` was given them (#1592): only keys the
|
||||
/// effect takes (those of its dialog defaults and of its params description), each of its
|
||||
/// default's type. Numbers out of range pass: the effect clamps them when it draws. An effect
|
||||
/// plug-in resolves its own against its manifest, and an unknown effect is the command's to report.
|
||||
/// default's type, and a `color` the effect can draw ([`check_effect_color`]). Numbers out of
|
||||
/// range pass: the effect clamps them when it draws. An effect plug-in resolves its own against
|
||||
/// its manifest, and an unknown effect is the command's to report.
|
||||
pub fn check_effect_params(id: &str, effect: &str, params: &Value) -> Result<()> {
|
||||
let Value::Object(given) = params else { return Ok(()) };
|
||||
if effect.starts_with(vectorcraft_plugins::effect::PREFIX) {
|
||||
@@ -240,6 +243,40 @@ pub fn check_effect_params(id: &str, effect: &str, params: &Value) -> Result<()>
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
check_effect_color(id, effect, params)
|
||||
}
|
||||
|
||||
/// Can an effect read `v` as its `color`: a string [`Color::from_hex`] reads (`#rrggbb`, `#rgb`,
|
||||
/// `#rrggbbaa`, black, white, red, green, blue), `[r, g, b]` whose first three entries are numbers
|
||||
/// (read on a 0..1 scale) or a color object (`{"model": "rgb", "r": …}`)? The effect draws its
|
||||
/// default color for any other value, except that an array of three or more entries draws an
|
||||
/// entry that isn't a number as 0.
|
||||
///
|
||||
/// [`Color::from_hex`]: vectorcraft_color::Color::from_hex
|
||||
fn is_effect_color(v: &Value) -> bool {
|
||||
match v {
|
||||
Value::String(s) => vectorcraft_color::Color::from_hex(s).is_some(),
|
||||
Value::Array(a) => a.len() >= 3 && a.iter().take(3).all(Value::is_number),
|
||||
Value::Object(_) => serde_json::from_value::<vectorcraft_color::Color>(v.clone()).is_ok(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// The `color` in `params` of built-in effect `effect`, when the effect has a `color` parameter,
|
||||
/// as command `id` was given it: a parameter error naming it unless the effect can read it
|
||||
/// ([`is_effect_color`]). `effect.apply` and `effect.setParams` run this themselves before they
|
||||
/// edit, so the app's own edits, the steps of a `command.batch` and a replayed journal are held to
|
||||
/// it too.
|
||||
pub(crate) fn check_effect_color(id: &str, effect: &str, params: &Value) -> Result<()> {
|
||||
let key = "color";
|
||||
let Some(v) = params.get(key) else { return Ok(()) };
|
||||
if effect.starts_with(vectorcraft_plugins::effect::PREFIX) {
|
||||
return Ok(());
|
||||
}
|
||||
let takes_color = vectorcraft_render::effects::effect_info(effect).is_some_and(|info| info.defaults.get(key).is_some_and(Value::is_string));
|
||||
if takes_color && !is_effect_color(v) {
|
||||
return Err(bad(id, format!("`{key}` must be a #rrggbb color")));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,58 @@ fn effect_params_no_longer_taken_still_replay_and_open() {
|
||||
assert_eq!(stored(&back)["blurr"], json!(3));
|
||||
}
|
||||
|
||||
/// An effect's `color` that the effect can't read (a string `Color::from_hex` doesn't read, an
|
||||
/// `[r, g, b]` without three numbers, an object that isn't a color, `null`) is refused by
|
||||
/// `effect.apply`, `appearance.addEffect` and `effect.setParams` themselves, not only by the check,
|
||||
/// and the document and its undo history stay as they were. The forms the effect reads pass. A
|
||||
/// document saved with an unreadable color still opens with it.
|
||||
#[test]
|
||||
fn an_effect_color_it_cannot_draw_is_refused() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({})).unwrap();
|
||||
let id = s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 50, "height": 40})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("effect.apply", &json!({"effect": "stylize.dropShadow", "params": {"color": "#ff0000"}})).unwrap();
|
||||
let state = |s: &Session| {
|
||||
let st = s.active().unwrap();
|
||||
(st.doc.clone(), st.history.undo.len())
|
||||
};
|
||||
let before = state(&s);
|
||||
let why = "`color` must be a #rrggbb color";
|
||||
for bad in [json!("not-a-color"), json!("#ff00"), json!([1, 0]), json!(["#ff0000", 0, 0]), json!({"gray": 50}), json!(null)] {
|
||||
for (cmd, params) in [
|
||||
("effect.setParams", json!({"index": 0, "params": {"color": bad}})),
|
||||
("effect.apply", json!({"effect": "stylize.outerGlow", "params": {"color": bad}})),
|
||||
("appearance.addEffect", json!({"effect": "adjust.shiftToColor", "params": {"color": bad}})),
|
||||
] {
|
||||
let e = s.execute(cmd, ¶ms).unwrap_err().to_string();
|
||||
assert!(e.contains(why), "{cmd} {params}: {e}");
|
||||
let checked = s.check_params(cmd, ¶ms).unwrap_err().to_string();
|
||||
assert!(checked.contains(why), "{cmd} {params}: {checked}");
|
||||
assert!(state(&s) == before, "{cmd} {params} changed the document or its undo history");
|
||||
}
|
||||
}
|
||||
let stored = |s: &Session| s.active().unwrap().doc.layers[0].children().unwrap()[0].appearance.effects[0].params["color"].clone();
|
||||
for good in [
|
||||
json!("#00ff00"),
|
||||
json!("#0f0"),
|
||||
json!("00ff00"),
|
||||
json!("#00ff00ff"),
|
||||
json!("green"),
|
||||
json!([0, 1, 0]),
|
||||
json!({"model": "rgb", "r": 0.0, "g": 1.0, "b": 0.0}),
|
||||
json!({"model": "cmyk", "c": 1.0, "m": 0.0, "y": 1.0, "k": 0.0}),
|
||||
] {
|
||||
let params = json!({"index": 0, "params": {"color": good}});
|
||||
s.check_params("effect.setParams", ¶ms).unwrap_or_else(|e| panic!("{good}: {e}"));
|
||||
s.execute("effect.setParams", ¶ms).unwrap_or_else(|e| panic!("{good}: {e}"));
|
||||
assert_eq!(stored(&s), good);
|
||||
}
|
||||
let mut doc = (*s.active().unwrap().doc).clone();
|
||||
doc.node_mut(vectorcraft_doc::NodeId(id)).unwrap().appearance.effects[0].params["color"] = json!("not-a-color");
|
||||
let back = vectorcraft_format::load(&vectorcraft_format::save(&doc, false)).unwrap();
|
||||
assert_eq!(back.layers[0].children().unwrap()[0].appearance.effects[0].params["color"], json!("not-a-color"));
|
||||
}
|
||||
|
||||
/// What a command adds to its own journal entry passes the check, so a recorded journal can be
|
||||
/// sent back through the control channel or MCP.
|
||||
#[test]
|
||||
|
||||
@@ -604,26 +604,14 @@ fn command(d: &Dialog) -> (&'static str, Value) {
|
||||
|
||||
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
let (cmd, p) = command(d);
|
||||
if super::warp_effect::is_warp(&d.str("__effect")) {
|
||||
let r = form::commit_preview(app, cmd, p.clone())?;
|
||||
if cmd == "effect.apply" {
|
||||
app.last_effect = Some((d.str("__effect"), p["params"].clone()));
|
||||
}
|
||||
return Ok(r);
|
||||
}
|
||||
let r = if app.session.in_interaction() {
|
||||
// Live preview already applied: keep it (the interaction commits as one undo step).
|
||||
let _ = app.session.preview(cmd, &p);
|
||||
app.session.commit_interaction().map(|_| Value::Null).map_err(|e| e.to_string())
|
||||
} else {
|
||||
app.run(cmd, p.clone())
|
||||
};
|
||||
// A live preview commits as one undo step. When the command refuses the values (a Color the
|
||||
// effect can't draw), the dialog stays open and the error is returned.
|
||||
let r = form::commit_preview(app, cmd, p.clone())?;
|
||||
// Last Effect repeats applied effects, not edits.
|
||||
if cmd == "effect.apply" {
|
||||
app.last_effect = Some((d.str("__effect"), p["params"].clone()));
|
||||
}
|
||||
app.ui.dialog = None;
|
||||
r
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -174,6 +174,27 @@ fn effect_preview_is_kept_as_one_undo_step() {
|
||||
assert_eq!(app.session.doc().unwrap().doc, before);
|
||||
}
|
||||
|
||||
/// Drop Shadow's Color typed as text the effect can't draw: OK returns the error and keeps the
|
||||
/// dialog open, with Preview on or off, and the document stays as it was.
|
||||
#[test]
|
||||
fn effect_dialog_refuses_a_color_it_cannot_draw() {
|
||||
for preview in [true, false] {
|
||||
let mut app = app();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap();
|
||||
app.run("select.all", json!({})).unwrap();
|
||||
let before = app.session.doc().unwrap().doc.clone();
|
||||
app.run("effect.dialog", json!({"effect": "stylize.dropShadow"})).unwrap();
|
||||
let d = app.ui.dialog.as_mut().unwrap();
|
||||
d.fields.insert("preview".into(), json!(preview));
|
||||
d.fields.insert("color".into(), json!("not-a-color"));
|
||||
frame(&mut app, Default::default());
|
||||
let e = confirm(&mut app).unwrap_err();
|
||||
assert!(e.contains("`color` must be a #rrggbb color"), "preview {preview}: {e}");
|
||||
assert!(app.ui.dialog.is_some() && app.last_effect.is_none(), "preview {preview}");
|
||||
assert_eq!(app.session.doc().unwrap().doc, before, "preview {preview}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn raster_filter_dialogs_preview_and_apply() {
|
||||
for (effect, key, value) in [
|
||||
|
||||
@@ -3605,6 +3605,7 @@ axis Both И двете
|
||||
@msg `{id}` has no envelope dialog `{id}` няма диалогов прозорец за обвивка
|
||||
@msg `{keep}` is not a side of this axis `{keep}` не е страна на тази ос
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` трябва да бъде `auto` или езиков код като `en` или `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` трябва да бъде цвят във формат #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` трябва да бъде цвят във формат #rrggbb
|
||||
@msg `{key}` must be a number `{key}` трябва да бъде число
|
||||
@msg `{key}` must be a string `{key}` трябва да бъде низ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3976,6 +3976,7 @@ imageTrace Outline Obrys
|
||||
@msg `{id}` has no envelope dialog `{id}` nemá dialogové okno obálky
|
||||
@msg `{keep}` is not a side of this axis `{keep}` není strana této osy
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` musí být `auto` nebo kód jazyka, například `en` nebo `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` musí být barva #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` musí být barva #rrggbb
|
||||
@msg `{key}` must be a number `{key}` musí být číslo
|
||||
@msg `{key}` must be a string `{key}` musí být řetězec
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3579,6 +3579,7 @@ theme Appearance Erscheinungsbild
|
||||
@msg `{id}` has no envelope dialog `{id}` hat kein Hüllendialogfeld
|
||||
@msg `{keep}` is not a side of this axis `{keep}` ist keine Seite dieser Achse
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` muss `auto` oder ein Sprachcode wie `en` oder `zh-hant` sein
|
||||
@msg `{key}` must be a #rrggbb color `{key}` muss eine Farbe der Form #rrggbb sein
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` muss eine Farbe der Form #rrggbb sein
|
||||
@msg `{key}` must be a number `{key}` muss eine Zahl sein
|
||||
@msg `{key}` must be a string `{key}` muss eine Zeichenfolge sein
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1988,6 +1988,7 @@ axis Both Και τα δύο
|
||||
@msg `{id}` has no envelope dialog Το `{id}` δεν έχει παράθυρο διαλόγου περιβλήματος
|
||||
@msg `{keep}` is not a side of this axis Το `{keep}` δεν είναι πλευρά αυτού του άξονα
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` Το `{key}` πρέπει να είναι `auto` ή κωδικός γλώσσας όπως `en` ή `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color Το `{key}` πρέπει να είναι χρώμα #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour Το `{key}` πρέπει να είναι χρώμα #rrggbb
|
||||
@msg `{key}` must be a number Το `{key}` πρέπει να είναι αριθμός
|
||||
@msg `{key}` must be a string Το `{key}` πρέπει να είναι συμβολοσειρά
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 1902 and column 19.
|
@@ -3676,6 +3676,7 @@ axis Both Ambos
|
||||
@msg `{id}` has no envelope dialog `{id}` no tiene cuadro de diálogo de envolvente
|
||||
@msg `{keep}` is not a side of this axis `{keep}` no es un lado de este eje
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` debe ser `auto` o un código de idioma como `en` o `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` debe ser un color #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` debe ser un color #rrggbb
|
||||
@msg `{key}` must be a number `{key}` debe ser un número
|
||||
@msg `{key}` must be a string `{key}` debe ser un texto
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3903,6 +3903,7 @@ imageTrace Outline Ääriviiva
|
||||
@msg `{id}` has no envelope dialog `{id}`: ei vääristyskuoren valintaikkunaa
|
||||
@msg `{keep}` is not a side of this axis `{keep}` ei ole tämän akselin puoli
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` on oltava `auto` tai kielikoodi, kuten `en` tai `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` on oltava #rrggbb-väri
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` on oltava #rrggbb-väri
|
||||
@msg `{key}` must be a number `{key}` on oltava luku
|
||||
@msg `{key}` must be a string `{key}` on oltava merkkijono
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3673,6 +3673,7 @@ axis Both Les deux
|
||||
@msg `{id}` has no envelope dialog `{id}` n’a pas de boîte de dialogue d’enveloppe
|
||||
@msg `{keep}` is not a side of this axis `{keep}` n’est pas un côté de cet axe
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` doit être `auto` ou un code de langue comme `en` ou `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` doit être une couleur #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` doit être une couleur #rrggbb
|
||||
@msg `{key}` must be a number `{key}` doit être un nombre
|
||||
@msg `{key}` must be a string `{key}` doit être une chaîne
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4169,6 +4169,7 @@ imageTrace Outline Körvonal
|
||||
@msg `{id}` has no envelope dialog ennek nincs burkoló-párbeszédablaka: `{id}`
|
||||
@msg `{keep}` is not a side of this axis `{keep}` nem ennek a tengelynek az oldala
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}`: `auto` vagy nyelvkód kell, például `en` vagy `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}`: #rrggbb szín kell
|
||||
@msg `{key}` must be a #rrggbb colour `{key}`: #rrggbb szín kell
|
||||
@msg `{key}` must be a number `{key}`: szám kell
|
||||
@msg `{key}` must be a string `{key}`: szöveg kell
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3679,6 +3679,7 @@ axis Both Entrambi
|
||||
@msg `{id}` has no envelope dialog `{id}` non ha una finestra di dialogo per l'involucro
|
||||
@msg `{keep}` is not a side of this axis `{keep}` non è un lato di questo asse
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` deve essere `auto` o un codice lingua come `en` o `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` deve essere un colore #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` deve essere un colore #rrggbb
|
||||
@msg `{key}` must be a number `{key}` deve essere un numero
|
||||
@msg `{key}` must be a string `{key}` deve essere una stringa
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3857,6 +3857,7 @@ swatch Bright Violet ビビッドバイオレット
|
||||
@msg no artboard アートボードがありません
|
||||
@msg installing from a path is not available on the web; pass the module as `dataBase64` Web 版ではファイルパスからはインストールできないため、モジュールは `dataBase64` で渡してください
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` は `auto` か、`en` や `zh-hant` などの言語コードにしてください
|
||||
@msg `{key}` must be a #rrggbb color `{key}` は #rrggbb 形式のカラーにしてください
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` は #rrggbb 形式のカラーにしてください
|
||||
@msg `{key}` must be a string `{key}` は文字列にしてください
|
||||
@msg `{key}` must be a whole number `{key}` は整数にしてください
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3789,6 +3789,7 @@ theme Appearance 외관
|
||||
@msg no artboard 아트보드가 없습니다
|
||||
@msg installing from a path is not available on the web; pass the module as `dataBase64` 웹에서는 경로로 설치할 수 없습니다. 모듈을 `dataBase64`로 전달하세요
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}`은(는) `auto` 또는 `en`, `zh-hant` 같은 언어 코드여야 합니다
|
||||
@msg `{key}` must be a #rrggbb color `{key}`은(는) #rrggbb 색상이어야 합니다
|
||||
@msg `{key}` must be a #rrggbb colour `{key}`은(는) #rrggbb 색상이어야 합니다
|
||||
@msg `{key}` must be a string `{key}`은(는) 문자열이어야 합니다
|
||||
@msg `{key}` must be a whole number `{key}`은(는) 정수여야 합니다
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3791,6 +3791,7 @@ imageTrace Outline Kontur
|
||||
@msg `{id}` has no envelope dialog `{id}` nie ma okna dialogowego koperty
|
||||
@msg `{keep}` is not a side of this axis `{keep}` nie jest stroną tej osi
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` musi mieć wartość `auto` lub kod języka, np. `en` albo `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` musi być kolorem #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` musi być kolorem #rrggbb
|
||||
@msg `{key}` must be a number `{key}` musi być liczbą
|
||||
@msg `{key}` must be a string `{key}` musi być ciągiem znaków
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3275,6 +3275,7 @@ axis Both Ambos
|
||||
@msg `{id}` has no envelope dialog `{id}` não tem caixa de diálogo de envelope
|
||||
@msg `{keep}` is not a side of this axis `{keep}` não é um lado deste eixo
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` deve ser `auto` ou um código de idioma como `en` ou `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` deve ser uma cor #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` deve ser uma cor #rrggbb
|
||||
@msg `{key}` must be a number `{key}` deve ser um número
|
||||
@msg `{key}` must be a string `{key}` deve ser uma string
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3675,6 +3675,7 @@ axis Both Оба
|
||||
@msg `{id}` has no envelope dialog `{id}` не имеет диалогового окна оболочки
|
||||
@msg `{keep}` is not a side of this axis `{keep}` не является стороной этой оси
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` должно быть `auto` или кодом языка, например `en` или `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` должно быть цветом #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` должно быть цветом #rrggbb
|
||||
@msg `{key}` must be a number `{key}` должно быть числом
|
||||
@msg `{key}` must be a string `{key}` должно быть строкой
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3605,6 +3605,7 @@ axis Both Båda
|
||||
@msg `{id}` has no envelope dialog `{id}` har ingen dialogruta för kuvert
|
||||
@msg `{keep}` is not a side of this axis `{keep}` är inte en sida av den här axeln
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` måste vara `auto` eller en språkkod som `en` eller `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` måste vara en färg i formatet #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` måste vara en färg i formatet #rrggbb
|
||||
@msg `{key}` must be a number `{key}` måste vara ett tal
|
||||
@msg `{key}` must be a string `{key}` måste vara en sträng
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1251,6 +1251,20 @@ fn unknown_parameter_errors_are_translated() {
|
||||
}
|
||||
}
|
||||
|
||||
/// The error for an effect `color` the effect can't draw, whose text the scan above doesn't read,
|
||||
/// is translated whole in each language of [`COMPLETE_MESSAGES`] and in Bulgarian.
|
||||
#[test]
|
||||
fn effect_color_param_error_is_translated() {
|
||||
use serde_json::json;
|
||||
let p = json!({"effect": "stylize.dropShadow", "params": {"color": "not-a-color"}});
|
||||
let e = vectorcraft_engine::check_params("effect.apply", &p).unwrap_err();
|
||||
let vectorcraft_engine::EngineError::BadParams { msg, .. } = &e else { panic!("{e}") };
|
||||
for code in COMPLETE_MESSAGES.iter().chain(&["bg"]) {
|
||||
let shown = message(Lang::from_code(code).unwrap(), &e.to_string());
|
||||
assert!(!shown.contains(msg.as_str()) && shown.contains("`color`") && shown.contains("effect.apply"), "{code}: {shown}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The notes of an EPS or `.ai` whose layers weren't read, which the importer pushes as warnings
|
||||
/// (the scan above doesn't read them), are translated whole, reason included, as the status bar
|
||||
/// shows them after opening (#2035).
|
||||
|
||||
@@ -3663,6 +3663,7 @@ axis Both Обидві
|
||||
@msg `{id}` has no envelope dialog `{id}` не має діалогового вікна оболонки
|
||||
@msg `{keep}` is not a side of this axis `{keep}` не є стороною цієї осі
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` має бути `auto` або кодом мови, наприклад `en` або `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` має бути кольором #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` має бути кольором #rrggbb
|
||||
@msg `{key}` must be a number `{key}` має бути числом
|
||||
@msg `{key}` must be a string `{key}` має бути рядком
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 721 and column 40.
|
@@ -3800,6 +3800,7 @@ theme Appearance Giao diện
|
||||
@msg `{id}` has no envelope dialog `{id}` không có hộp thoại Envelope
|
||||
@msg `{keep}` is not a side of this axis `{keep}` không phải là một cạnh của trục này
|
||||
@msg `{key}` must be `auto` or a language code such as `en` or `zh-hant` `{key}` phải là `auto` hoặc mã ngôn ngữ như `en` hoặc `zh-hant`
|
||||
@msg `{key}` must be a #rrggbb color `{key}` phải là màu #rrggbb
|
||||
@msg `{key}` must be a #rrggbb colour `{key}` phải là màu #rrggbb
|
||||
@msg `{key}` must be a number `{key}` phải là một số
|
||||
@msg `{key}` must be a string `{key}` phải là một chuỗi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3780 and column 10.
|
+18
-2
@@ -815,13 +815,29 @@ is refused the same way:
|
||||
→ invalid parameters for `effect.apply`: unknown parameter `blurr`; the command takes: radius
|
||||
```
|
||||
|
||||
The `color` of Drop Shadow, Inner Glow, Outer Glow and Shift to Color must be one the effect can read: a hex color
|
||||
(`#rrggbb`, `#rgb` or `#rrggbbaa`, with or without the `#`), `black`, `white`, `red`, `green` or `blue`, `[r, g, b]`
|
||||
(three numbers, each read on a 0 to 1 scale), or a color object (`{"model": "rgb", "r": 1, "g": 0, "b": 0}`).
|
||||
`effect.apply` and `effect.setParams` refuse any other value themselves (where the parameter check runs first, a number
|
||||
or a boolean is refused as not a string), so the app's effect dialogs and Appearance panel, a step of
|
||||
`command.batch` and a replayed journal get the same error, and the document and its undo history stay as they were:
|
||||
|
||||
```json
|
||||
{"id": "effect.setParams", "params": {"index": 0, "params": {"color": "#ff00"}}}
|
||||
→ invalid parameters for `effect.setParams`: `color` must be a #rrggbb color
|
||||
```
|
||||
|
||||
A document saved with such a color opens as before, and the effect draws its default color (an array of three or more
|
||||
entries reads an entry that isn't a number as 0).
|
||||
|
||||
A number outside the range the effect documents is still stored as given and clamped when the effect draws. A
|
||||
plug-in effect's parameters are resolved against its manifest instead, and `effect.setParams` as a step of
|
||||
`command.batch` isn't checked (the effect it edits may only exist once the steps before it ran). A description with a `…` entry takes more keys than it lists: those of the command it names
|
||||
`command.batch` isn't checked before the batch runs (the effect it edits may only exist once the steps before it ran);
|
||||
the command still refuses an effect `color` it can't read. A description with a `…` entry takes more keys than it lists: those of the command it names
|
||||
(`…settings as file.new`), or any key when it names none, as `document.export` and `document.save` do for the options
|
||||
of the format they write (one object can carry several formats' options). A command that takes its own reply back
|
||||
(`document.setup`, `text.areaOptions`) says so the same way. The app's own journal isn't checked: an action or
|
||||
journal recorded by an older version replays as it did.
|
||||
journal recorded by an older version replays as it did, except for an effect `color` that the effect can't read.
|
||||
|
||||
A step can use an earlier step's result, in `run` as in the `command_batch` tool. A parameter string that is exactly
|
||||
`$N` or `$N.path` takes that value from the result of step `N` (counting from 0, in the order they ran; `run --in`'s
|
||||
|
||||
Reference in New Issue
Block a user