mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-31 13:17:19 -06:00
Add-ons: Color Effects — live exposure, desaturate and invert, apply as filter, panel
A built-in add-on in Effect › Color Effects and Object › Plug-ins › Color Effects: - Exposure (stops of linear light, offset and gamma), Desaturate and Invert Colors as live colour adjustments, evaluated in stack order with those of Effect › Color Adjustments. - addon.color.filter applies any colour adjustment to the colours themselves, through the Edit Colors pass, as one undo step. - A panel picks an adjustment and its values, then adds it as a live effect or applies it as a filter. The add-on lives in its own modules (effects, engine and ui-egui addons folders) and leaves the existing effects, commands and menus as they were.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
//! Effects of VectorCraft's built-in add-ons, one module per add-on.
|
||||
//!
|
||||
//! - [`color`]: Color Effects' live Exposure, Desaturate and Invert Colors, colour adjustments
|
||||
//! evaluated with the others ([`crate::adjust`]).
|
||||
|
||||
pub mod color;
|
||||
@@ -0,0 +1,132 @@
|
||||
//! Color Effects (a built-in add-on): live Exposure, Desaturate and Invert Colors, in Effect › Color
|
||||
//! Effects. They are colour adjustments ([`crate::is_adjustment`]): they recolour what an object
|
||||
//! paints as the others do, in stack order with them.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::catalog::{EffectInfo, Lengths};
|
||||
use crate::util::num;
|
||||
|
||||
/// Exposure: brighten or darken in stops of light, with an offset and a gamma.
|
||||
pub const EXPOSURE: &str = "addon.color.exposure";
|
||||
/// Desaturate: every colour to the grey of its lightness.
|
||||
pub const DESATURATE: &str = "addon.color.desaturate";
|
||||
/// Invert Colors: every colour to its RGB inverse.
|
||||
pub const INVERT: &str = "addon.color.invert";
|
||||
|
||||
/// The add-on's effects, in menu order.
|
||||
pub const EFFECTS: [&str; 3] = [DESATURATE, EXPOSURE, INVERT];
|
||||
|
||||
/// Is `id` one of the add-on's effects?
|
||||
pub fn is_color_effect(id: &str) -> bool {
|
||||
EFFECTS.contains(&id)
|
||||
}
|
||||
|
||||
/// The add-on's catalogue entries.
|
||||
pub(crate) fn catalog() -> Vec<EffectInfo> {
|
||||
const MENU: &[&str] = &["Effect", "Color Effects"];
|
||||
let e = |id, label, params, defaults| EffectInfo { id, label, menu: MENU, params, defaults, raster: false, lengths: Lengths::default() };
|
||||
vec![
|
||||
e(DESATURATE, "Desaturate", "{} turns every colour the object paints to the grey of its lightness (each colour keeps its model)", json!({})),
|
||||
e(
|
||||
EXPOSURE,
|
||||
"Exposure…",
|
||||
"{exposure: stops -20..20 (0; mostly the highlights: each stop doubles or halves the light), offset: -0.5..0.5 (0; lifts or sinks the shadows and midtones), gamma: 0.1..10 (1; above 1 lightens the midtones)} recolours as Brightness/Contrast does, in linear light",
|
||||
json!({"exposure": 0.0, "offset": 0.0, "gamma": 1.0}),
|
||||
),
|
||||
e(INVERT, "Invert Colors", "{} turns every colour the object paints to its RGB inverse (each colour keeps its model)", json!({})),
|
||||
]
|
||||
}
|
||||
|
||||
/// One of the add-on's adjustments, its parameters normalised.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum Adjust {
|
||||
/// Linear light times `gain`, plus `offset`, to the power 1 / `gamma`.
|
||||
Exposure {
|
||||
gain: f32,
|
||||
offset: f32,
|
||||
gamma: f32,
|
||||
},
|
||||
Desaturate,
|
||||
Invert,
|
||||
}
|
||||
|
||||
impl Adjust {
|
||||
pub(crate) fn parse(id: &str, p: &Value) -> Option<Self> {
|
||||
Some(match id {
|
||||
EXPOSURE => Adjust::Exposure {
|
||||
gain: 2f64.powf(num(p, "exposure", 0.0).clamp(-20.0, 20.0)) as f32,
|
||||
offset: num(p, "offset", 0.0).clamp(-0.5, 0.5) as f32,
|
||||
gamma: num(p, "gamma", 1.0).clamp(0.1, 10.0) as f32,
|
||||
},
|
||||
DESATURATE => Adjust::Desaturate,
|
||||
INVERT => Adjust::Invert,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn apply(&self, rgb: [f32; 3]) -> [f32; 3] {
|
||||
match self {
|
||||
Adjust::Exposure { gain, offset, gamma } => rgb.map(|v| to_srgb((to_linear(v) * gain + offset).max(0.0).powf(1.0 / gamma))),
|
||||
Adjust::Desaturate => {
|
||||
let [r, g, b] = rgb;
|
||||
[(r.max(g).max(b) + r.min(g).min(b)) / 2.0; 3]
|
||||
}
|
||||
Adjust::Invert => rgb.map(|v| 1.0 - v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_linear(v: f32) -> f32 {
|
||||
let v = v.clamp(0.0, 1.0);
|
||||
if v <= 0.04045 { v / 12.92 } else { ((v + 0.055) / 1.055).powf(2.4) }
|
||||
}
|
||||
|
||||
fn to_srgb(v: f32) -> f32 {
|
||||
let v = v.clamp(0.0, 1.0);
|
||||
if v <= 0.003_130_8 { v * 12.92 } else { 1.055 * v.powf(1.0 / 2.4) - 0.055 }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::color_map;
|
||||
use vectorcraft_doc::Effect;
|
||||
|
||||
fn map(id: &str, params: Value) -> crate::ColorMap {
|
||||
color_map(&[Effect { id: id.into(), params, visible: true }]).unwrap()
|
||||
}
|
||||
|
||||
fn close(a: [f32; 3], b: [f32; 3]) -> bool {
|
||||
a.iter().zip(b).all(|(x, y)| (x - y).abs() < 0.01)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_effects_are_colour_adjustments_in_their_own_menu() {
|
||||
for id in EFFECTS {
|
||||
assert!(crate::is_adjustment(id), "{id}");
|
||||
assert_eq!(crate::effect_info(id).unwrap().menu, ["Effect", "Color Effects"]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exposure_works_in_stops_of_linear_light() {
|
||||
let grey = [0.5; 3];
|
||||
assert!(close(map(EXPOSURE, json!({})).apply_rgb(grey), grey), "neutral by default");
|
||||
// One stop doubles the light: sRGB 0.5 (linear 0.214) becomes linear 0.428, sRGB 0.686.
|
||||
assert!(close(map(EXPOSURE, json!({"exposure": 1})).apply_rgb(grey), [0.686; 3]));
|
||||
assert!(close(map(EXPOSURE, json!({"exposure": -20})).apply_rgb([1.0; 3]), [0.0; 3]));
|
||||
assert!(map(EXPOSURE, json!({"offset": 0.1})).apply_rgb([0.0; 3])[0] > 0.3, "the offset lifts the shadows");
|
||||
assert!(map(EXPOSURE, json!({"gamma": 2})).apply_rgb(grey)[0] > 0.6);
|
||||
assert!(close(map(EXPOSURE, json!({"exposure": 1e300, "gamma": 0})).apply_rgb(grey), [1.0; 3]), "out of range values are clamped");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desaturate_and_invert() {
|
||||
assert!(close(map(DESATURATE, json!({})).apply_rgb([1.0, 0.0, 0.0]), [0.5; 3]));
|
||||
assert!(close(map(DESATURATE, json!({})).apply_rgb([1.0, 1.0, 0.0]), [0.5; 3]), "lightness is kept, not luminance");
|
||||
assert!(close(map(INVERT, json!({})).apply_rgb([1.0, 0.25, 0.0]), [0.0, 0.75, 1.0]));
|
||||
let both = map(INVERT, json!({})).then(&map(INVERT, json!({})));
|
||||
assert!(close(both.apply_rgb([0.2, 0.4, 0.6]), [0.2, 0.4, 0.6]));
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ pub const ADJUSTMENTS: [&str; 6] =
|
||||
|
||||
/// Is `id` a colour adjustment effect?
|
||||
pub fn is_adjustment(id: &str) -> bool {
|
||||
ADJUSTMENTS.contains(&id)
|
||||
ADJUSTMENTS.contains(&id) || crate::addons::color::is_color_effect(id)
|
||||
}
|
||||
|
||||
fn visible_adjustment(e: &Effect) -> bool {
|
||||
@@ -88,6 +88,8 @@ enum Adjust {
|
||||
ShiftToColor { target: [f32; 3], amount: f32, preserve: bool },
|
||||
/// Warm/cool and magenta/green shifts, -1..1.
|
||||
TemperatureTint { temperature: f32, tint: f32 },
|
||||
/// One of the Color Effects add-on's.
|
||||
Addon(crate::addons::color::Adjust),
|
||||
}
|
||||
|
||||
/// The colour adjustments of an effect list, composed in order.
|
||||
@@ -175,7 +177,7 @@ impl Adjust {
|
||||
preserve: flag(p, "preserveLightness", true),
|
||||
},
|
||||
"adjust.temperatureTint" => Adjust::TemperatureTint { temperature: amount(p, "temperature"), tint: amount(p, "tint") },
|
||||
_ => return None,
|
||||
_ => Adjust::Addon(crate::addons::color::Adjust::parse(id, p)?),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -225,6 +227,7 @@ impl Adjust {
|
||||
let (t, m) = (temperature * 0.3, tint * 0.3);
|
||||
[r * (1.0 + t), g * (1.0 - m), b * (1.0 - t)]
|
||||
}
|
||||
Adjust::Addon(a) => a.apply([r, g, b]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,6 +791,7 @@ pub fn effect_catalog() -> Vec<EffectInfo> {
|
||||
v.push(g(id, label, PATHFINDER, "{} (groups and layers: live Pathfinder over the members)", json!({})));
|
||||
}
|
||||
}
|
||||
v.extend(crate::addons::color::catalog());
|
||||
v.push(g(TRAP, "Trap…", PATHFINDER, trap::EFFECT_PARAMS_DOC, trap::effect_defaults()));
|
||||
v.push(g(
|
||||
CROP_MARKS,
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
//! anchored at the object's centre.
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod addons;
|
||||
mod adjust;
|
||||
mod bake;
|
||||
mod clip;
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
//! with commands under `addon.<name>.*` (see `docs/mcp.md`).
|
||||
|
||||
mod cleanup;
|
||||
mod color;
|
||||
|
||||
use super::CommandSpec;
|
||||
|
||||
/// The commands of every built-in add-on.
|
||||
pub fn specs() -> Vec<CommandSpec> {
|
||||
cleanup::specs()
|
||||
let mut v = cleanup::specs();
|
||||
v.extend(color::specs());
|
||||
v
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//! Color Effects (`addon.color.*`), a built-in add-on: its live effects (Exposure, Desaturate and
|
||||
//! Invert Colors, in Effect › Color Effects) are the effects crate's; here, Apply as Filter writes
|
||||
//! any colour adjustment into the colours themselves. Its panel and its submenu, Object › Plug-ins ›
|
||||
//! Color Effects, are the UI's.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_render::effects;
|
||||
|
||||
use super::super::colorcmds::recolor;
|
||||
use super::super::{CommandSpec, bad, checked_ids_or_selection, cmd, has_selection, text_param};
|
||||
use crate::{Result, Session};
|
||||
|
||||
pub fn specs() -> Vec<CommandSpec> {
|
||||
vec![cmd!(
|
||||
"addon.color.filter",
|
||||
"Apply as Filter",
|
||||
["Object", "Plug-ins", "Color Effects"],
|
||||
None,
|
||||
"{effect: a colour adjustment's effect id (adjust.brightnessContrast, adjust.curves, adjust.hueSaturation, adjust.levels, adjust.shiftToColor, adjust.temperatureTint, addon.color.exposure, addon.color.desaturate or addon.color.invert), params?: {…} (as effect.apply; missing keys take the dialog defaults), fill?: true, stroke?: true, includeImages?: true, includePatterns?: true, ids?: [id…] (default: the selection)} recolour the objects and everything inside them as the live effect would draw them, but in their colours, as edit.colors.invert does (fills, strokes, type, gradient meshes, embedded images and pattern tiles), as one undo step; their effects stay → {changed}",
|
||||
has_selection,
|
||||
filter
|
||||
)]
|
||||
}
|
||||
|
||||
fn filter(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "addon.color.filter";
|
||||
let id = text_param(p, "effect", C)?.ok_or_else(|| bad(C, "missing `effect`"))?;
|
||||
if !effects::is_adjustment(id) {
|
||||
return Err(bad(C, format!("`{id}` is not a colour adjustment")));
|
||||
}
|
||||
let params = match p.get("params") {
|
||||
None | Some(Value::Null) => json!({}),
|
||||
Some(v @ Value::Object(_)) => v.clone(),
|
||||
Some(_) => return Err(bad(C, "`params` must be an object")),
|
||||
};
|
||||
let fx = effects::new_effect(id, ¶ms).ok_or_else(|| bad(C, format!("unknown effect `{id}`")))?;
|
||||
let ids = checked_ids_or_selection(s, p, C)?;
|
||||
// Settings that change nothing still make the pass, which then leaves every colour as it was.
|
||||
let Some(map) = effects::color_map(&[fx]) else { return Ok(json!({ "changed": 0 })) };
|
||||
let mut given = p.clone();
|
||||
if let Some(o) = given.as_object_mut() {
|
||||
o.insert("ids".into(), json!(ids.iter().map(|i| i.0).collect::<Vec<_>>()));
|
||||
}
|
||||
let label = effects::effect_info(id).map_or("Apply as Filter", |e| e.label.trim_end_matches('…'));
|
||||
recolor(s, &given, label, &|c| map.apply(c))
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//! Color Effects: its live effects through effect.apply, and Apply as Filter.
|
||||
|
||||
use serde_json::json;
|
||||
use vectorcraft_doc::NodeId;
|
||||
use vectorcraft_geom::Rect;
|
||||
|
||||
use crate::Session;
|
||||
|
||||
/// A document with a selected red rectangle, unstroked.
|
||||
fn red_rect() -> (Session, NodeId) {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
|
||||
let id = NodeId(s.execute("shape.rectangle", &json!({"x": 20, "y": 20, "width": 60, "height": 60})).unwrap()["id"].as_u64().unwrap());
|
||||
s.execute("paint.setFill", &json!({"color": "#ff0000"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
(s, id)
|
||||
}
|
||||
|
||||
fn fill_hex(s: &Session, id: NodeId) -> String {
|
||||
s.doc().unwrap().doc.node(id).unwrap().appearance.fill_paint().color().unwrap().to_hex()
|
||||
}
|
||||
|
||||
fn pixel(s: &Session) -> [u8; 4] {
|
||||
vectorcraft_render::Renderer::new().render_region(&s.doc().unwrap().doc, Rect::new(0.0, 0.0, 100.0, 100.0), 1.0, true).pixel(50, 50)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_live_effects_draw_without_changing_the_colours() {
|
||||
for (effect, params, drawn) in [
|
||||
("addon.color.invert", json!({}), [0, 255, 255, 255]),
|
||||
("addon.color.desaturate", json!({}), [128, 128, 128, 255]),
|
||||
("addon.color.exposure", json!({"exposure": -20}), [0, 0, 0, 255]),
|
||||
] {
|
||||
let (mut s, id) = red_rect();
|
||||
s.execute("effect.apply", &json!({"effect": effect, "params": params})).unwrap();
|
||||
assert_eq!(fill_hex(&s, id), "#ff0000", "{effect}");
|
||||
assert_eq!(pixel(&s), drawn, "{effect}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_filter_recolours_the_object_as_one_undo_step() {
|
||||
let (mut s, id) = red_rect();
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
let v = s.execute("addon.color.filter", &json!({"effect": "addon.color.invert"})).unwrap();
|
||||
assert_eq!(v["changed"], 1);
|
||||
assert_eq!(fill_hex(&s, id), "#00ffff");
|
||||
let n = s.doc().unwrap().doc.node(id).unwrap().clone();
|
||||
assert!(n.appearance.effects.is_empty(), "no effect is added");
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), undo + 1);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(fill_hex(&s, id), "#ff0000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_filter_takes_any_colour_adjustment_with_its_params() {
|
||||
let (mut s, id) = red_rect();
|
||||
s.execute("addon.color.filter", &json!({"effect": "adjust.hueSaturation", "params": {"hue": 120}})).unwrap();
|
||||
assert_eq!(fill_hex(&s, id), "#00ff00");
|
||||
// Live effects already on the object stay live, on top of the new colours.
|
||||
s.execute("effect.apply", &json!({"effect": "addon.color.invert"})).unwrap();
|
||||
s.execute("addon.color.filter", &json!({"effect": "addon.color.desaturate", "ids": [id.0]})).unwrap();
|
||||
assert_eq!(fill_hex(&s, id), "#808080");
|
||||
assert_eq!(s.doc().unwrap().doc.node(id).unwrap().appearance.effects.len(), 1);
|
||||
// The stroke only: the fill stays.
|
||||
s.execute("addon.color.filter", &json!({"effect": "addon.color.invert", "fill": false})).unwrap();
|
||||
assert_eq!(fill_hex(&s, id), "#808080");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_requests_are_refused() {
|
||||
let (mut s, id) = red_rect();
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
for p in [
|
||||
json!({}),
|
||||
json!({"effect": 3}),
|
||||
json!({"effect": "distort.roughen"}),
|
||||
json!({"effect": "adjust.nothing"}),
|
||||
json!({"effect": "addon.color.invert", "params": [1]}),
|
||||
json!({"effect": "addon.color.invert", "ids": [999_999]}),
|
||||
json!({"effect": "addon.color.invert", "ids": ["x"]}),
|
||||
] {
|
||||
assert!(s.execute("addon.color.filter", &p).is_err(), "{p}");
|
||||
}
|
||||
assert_eq!(fill_hex(&s, id), "#ff0000");
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), undo);
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
assert!(s.execute("addon.color.filter", &json!({"effect": "addon.color.invert"})).is_err(), "nothing selected");
|
||||
}
|
||||
@@ -2,10 +2,11 @@
|
||||
//! Object › Plug-ins, and acts through its engine commands (`addon.<name>.*`).
|
||||
|
||||
pub mod cleanup;
|
||||
pub mod color;
|
||||
|
||||
use crate::menus::Item;
|
||||
|
||||
/// The add-ons' submenus, then a separator: the head of Object › Plug-ins.
|
||||
pub fn plugin_menu() -> Vec<Item> {
|
||||
vec![Item::Sub("Artwork Cleanup", cleanup::menu()), Item::Sep]
|
||||
vec![Item::Sub("Artwork Cleanup", cleanup::menu()), Item::Sub("Color Effects", color::menu()), Item::Sep]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
//! Color Effects' panel and submenu (Object › Plug-ins › Color Effects). The panel picks a colour
|
||||
//! adjustment and its values, then adds it to the selection as a live effect or applies it as a
|
||||
//! filter, into the colours themselves (`addon.color.filter`). The submenu applies the add-on's
|
||||
//! live effects (Effect › Color Effects has them too) and opens the panel.
|
||||
|
||||
use egui::Ui;
|
||||
use serde_json::{Map, Value, json};
|
||||
|
||||
use crate::VectorcraftApp;
|
||||
use crate::menus::Item;
|
||||
use crate::panels::{empty_state, pstate, set_pstate};
|
||||
use crate::widgets;
|
||||
|
||||
/// The panel's id (`window.panel {panel: "colorEffects"}`).
|
||||
pub const ID: &str = "colorEffects";
|
||||
|
||||
/// Where the panel keeps its choice and values (panel state).
|
||||
const STATE: &str = "color-effects";
|
||||
|
||||
/// A value of an adjustment: (parameter, label, range, decimals, default).
|
||||
type Field = (&'static str, &'static str, (f64, f64), usize, f64);
|
||||
|
||||
/// The adjustments the panel offers: (effect, label, values). Curves and Shift to Color, which take
|
||||
/// a curve or a colour, keep to their dialogs (Effect › Color Adjustments).
|
||||
const ADJUSTMENTS: [(&str, &str, &[Field]); 7] = [
|
||||
(
|
||||
"adjust.brightnessContrast",
|
||||
"Brightness/Contrast",
|
||||
&[("brightness", "Brightness", (-100.0, 100.0), 0, 0.0), ("contrast", "Contrast", (-100.0, 100.0), 0, 0.0)],
|
||||
),
|
||||
(
|
||||
"adjust.hueSaturation",
|
||||
"Hue/Saturation",
|
||||
&[
|
||||
("hue", "Hue", (-180.0, 180.0), 0, 0.0),
|
||||
("saturation", "Saturation", (-100.0, 100.0), 0, 0.0),
|
||||
("lightness", "Lightness", (-100.0, 100.0), 0, 0.0),
|
||||
],
|
||||
),
|
||||
(
|
||||
"adjust.levels",
|
||||
"Levels",
|
||||
&[
|
||||
("inputBlack", "Input Black", (0.0, 255.0), 0, 0.0),
|
||||
("inputWhite", "Input White", (0.0, 255.0), 0, 255.0),
|
||||
("gamma", "Gamma", (0.1, 10.0), 2, 1.0),
|
||||
("outputBlack", "Output Black", (0.0, 255.0), 0, 0.0),
|
||||
("outputWhite", "Output White", (0.0, 255.0), 0, 255.0),
|
||||
],
|
||||
),
|
||||
(
|
||||
"adjust.temperatureTint",
|
||||
"Temperature/Tint",
|
||||
&[("temperature", "Temperature", (-100.0, 100.0), 0, 0.0), ("tint", "Tint", (-100.0, 100.0), 0, 0.0)],
|
||||
),
|
||||
(
|
||||
"addon.color.exposure",
|
||||
"Exposure",
|
||||
&[("exposure", "Exposure", (-20.0, 20.0), 2, 0.0), ("offset", "Offset", (-0.5, 0.5), 3, 0.0), ("gamma", "Gamma", (0.1, 10.0), 2, 1.0)],
|
||||
),
|
||||
("addon.color.desaturate", "Desaturate", &[]),
|
||||
("addon.color.invert", "Invert Colors", &[]),
|
||||
];
|
||||
|
||||
/// Adjustment `i` of [`ADJUSTMENTS`] (the first past the end).
|
||||
fn adjustment(i: usize) -> (&'static str, &'static str, &'static [Field]) {
|
||||
ADJUSTMENTS.get(i).copied().unwrap_or(ADJUSTMENTS[0])
|
||||
}
|
||||
|
||||
/// Object › Plug-ins › Color Effects.
|
||||
pub fn menu() -> Vec<Item> {
|
||||
vec![
|
||||
Item::Cmd("Color Effects Panel", "window.panel", json!({ "panel": ID })),
|
||||
Item::Sep,
|
||||
Item::Cmd("Exposure…", "effect.dialog", json!({ "effect": "addon.color.exposure" })),
|
||||
Item::Cmd("Desaturate", "effect.apply", json!({ "effect": "addon.color.desaturate" })),
|
||||
Item::Cmd("Invert Colors", "effect.apply", json!({ "effect": "addon.color.invert" })),
|
||||
]
|
||||
}
|
||||
|
||||
/// The panel's choice and the values set for each adjustment.
|
||||
#[derive(Clone, Default)]
|
||||
struct Picked {
|
||||
/// Index in [`ADJUSTMENTS`].
|
||||
index: usize,
|
||||
/// Values set, by effect id then parameter.
|
||||
values: Map<String, Value>,
|
||||
}
|
||||
|
||||
impl Picked {
|
||||
/// The params of the adjustment picked: its values, the defaults where none is set.
|
||||
fn params(&self) -> (&'static str, Value) {
|
||||
let (id, _, fields) = adjustment(self.index);
|
||||
let set = self.values.get(id).and_then(Value::as_object);
|
||||
let p: Map<String, Value> =
|
||||
fields.iter().map(|(k, _, _, _, default)| (k.to_string(), set.and_then(|m| m.get(*k)).cloned().unwrap_or(json!(default)))).collect();
|
||||
(id, Value::Object(p))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
if app.session.active().is_none_or(|d| d.selection.is_empty()) {
|
||||
empty_state(ui, "sun", tl!("No selection"), tl!("Select objects to adjust their colors."));
|
||||
return;
|
||||
}
|
||||
let mut st: Picked = pstate(ui.ctx(), STATE);
|
||||
let labels: Vec<&str> = ADJUSTMENTS.iter().map(|a| a.1).collect();
|
||||
let (id, label, fields) = adjustment(st.index);
|
||||
const LABEL_W: f32 = 84.0;
|
||||
widgets::label_row(ui, tl!("Adjustment"), LABEL_W, |ui| {
|
||||
if let Some(i) = widgets::dropdown(ui, "color-effects-pick", label, &labels, 150.0) {
|
||||
st.index = i;
|
||||
}
|
||||
});
|
||||
let (_, params) = st.params();
|
||||
for (key, name, (min, max), decimals, _) in fields {
|
||||
let v = params.get(*key).and_then(Value::as_f64);
|
||||
widgets::label_row(ui, tl!(name), LABEL_W, |ui| {
|
||||
if let Some(n) = widgets::range_field(ui, ("color-effects", id, key), v, *min..=*max, "", *decimals, 70.0) {
|
||||
let set = st.values.entry(id).or_insert_with(|| json!({}));
|
||||
if let Some(m) = set.as_object_mut() {
|
||||
m.insert(key.to_string(), json!(n));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
ui.add_space(4.0);
|
||||
let (id, params) = st.params();
|
||||
ui.horizontal(|ui| {
|
||||
let run = |app: &mut VectorcraftApp, cmd: &str| {
|
||||
if let Err(e) = app.run(cmd, json!({ "effect": id, "params": params })) {
|
||||
app.status(e);
|
||||
}
|
||||
};
|
||||
if widgets::flat_button(ui, tl!("Add as Effect"), 100.0).clicked() {
|
||||
run(app, "effect.apply");
|
||||
}
|
||||
if widgets::flat_button(ui, tl!("Apply as Filter"), 100.0).clicked() {
|
||||
run(app, "addon.color.filter");
|
||||
}
|
||||
if widgets::flat_button(ui, tl!("Reset"), 56.0).clicked() {
|
||||
st.values.remove(id);
|
||||
}
|
||||
});
|
||||
set_pstate(ui.ctx(), STATE, st);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -0,0 +1,61 @@
|
||||
use serde_json::json;
|
||||
use vectorcraft_engine::Session;
|
||||
|
||||
use super::{ADJUSTMENTS, ID, Picked, STATE, show};
|
||||
use crate::panels::set_pstate;
|
||||
use crate::tests_labels::painted_text;
|
||||
use crate::{VectorcraftApp, menus};
|
||||
|
||||
/// An app with a selected red rectangle.
|
||||
fn app() -> VectorcraftApp {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 40, "height": 40})).unwrap();
|
||||
app.run("paint.setFill", json!({"color": "#ff0000"})).unwrap();
|
||||
app
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_menus_list_the_effects_and_open_the_panel() {
|
||||
let mut app = app();
|
||||
let entries = menus::menu_entries(&app);
|
||||
let at = |path: &[&str], label: &str| entries.iter().find(|e| e.path == path && e.label == label);
|
||||
let plugins = ["Object", "Plug-ins", "Color Effects"];
|
||||
let item = at(&plugins, "Color Effects Panel").expect("listed");
|
||||
for label in ["Exposure…", "Desaturate", "Invert Colors"] {
|
||||
assert!(at(&plugins, label).is_some(), "Object › Plug-ins › Color Effects › {label}");
|
||||
assert!(at(&["Effect", "Color Effects"], label).is_some(), "Effect › Color Effects › {label}");
|
||||
}
|
||||
// The existing submenus are as they were.
|
||||
assert!(at(&["Effect", "Color Adjustments"], "Exposure…").is_none());
|
||||
menus::invoke(&mut app, "window.panel", item.params.clone());
|
||||
assert!(crate::panel_docking::showing(&app.ui, ID), "the panel opens");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_adjustment_offered_is_a_colour_adjustment_with_its_defaults() {
|
||||
for (i, (id, _, fields)) in ADJUSTMENTS.iter().enumerate() {
|
||||
assert!(vectorcraft_effects::is_adjustment(id), "{id}");
|
||||
let defaults = vectorcraft_effects::effect_info(id).unwrap().defaults;
|
||||
let (picked, params) = Picked { index: i, ..Picked::default() }.params();
|
||||
assert_eq!(picked, *id);
|
||||
for (key, ..) in fields.iter() {
|
||||
assert_eq!(params[key], defaults[key], "{id} {key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_panel_shows_the_values_and_its_buttons() {
|
||||
let mut app = app();
|
||||
let exposure = ADJUSTMENTS.iter().position(|a| a.0 == "addon.color.exposure").unwrap();
|
||||
let text = painted_text(&mut app, |app, ui| {
|
||||
set_pstate(ui.ctx(), STATE, Picked { index: exposure, ..Picked::default() });
|
||||
show(app, ui);
|
||||
});
|
||||
for s in ["Exposure", "Offset", "Gamma", "Add as Effect", "Apply as Filter"] {
|
||||
assert!(text.contains(s), "{s} in {text}");
|
||||
}
|
||||
app.run("select.none", json!({})).unwrap();
|
||||
assert!(painted_text(&mut app, show).contains("No selection"));
|
||||
}
|
||||
@@ -161,7 +161,8 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
// Plug-in effects get fields from their parameter schema; colour adjustments their sliders.
|
||||
let changed = match vectorcraft_plugins::effect::installed(&id) {
|
||||
Some(plugin) => form::schema_fields(app, ui, d, plugin.manifest()),
|
||||
None if vectorcraft_effects::is_adjustment(&id) => adjust_fields(ui, d),
|
||||
// The Color Effects add-on's take the plain form of their parameters.
|
||||
None if vectorcraft_effects::is_adjustment(&id) && !vectorcraft_effects::addons::color::is_color_effect(&id) => adjust_fields(ui, d),
|
||||
None if id == GLASS => glass_fields(app, ui, d, GLASS),
|
||||
None if id == TEXTURIZER => glass_fields(app, ui, d, TEXTURIZER),
|
||||
None if id == TRANSFORM => transform_fields(ui, d, app.session.general_unit()),
|
||||
|
||||
@@ -5637,3 +5637,20 @@ anchor Points: Точки:
|
||||
Simplify Anchors (Keep Shape) Опростяване на опорните точки (запазване на формата)
|
||||
Deep Ungroup Разгрупиране на всички нива
|
||||
Rejoin Path Pieces Повторно свързване на части от пътища
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Цветови ефекти
|
||||
Color Effects Panel Панел „Цветови ефекти“
|
||||
Exposure Експонация
|
||||
Exposure… Експонация…
|
||||
Desaturate Обезцветяване
|
||||
Adjustment Корекция
|
||||
Add as Effect Добавяне като ефект
|
||||
Apply as Filter Прилагане като филтър
|
||||
Select objects to adjust their colors. Изберете обекти, за да коригирате цветовете им.
|
||||
Brightness/Contrast Яркост/Контраст
|
||||
Hue/Saturation Оттенък/Наситеност
|
||||
Temperature/Tint Температура/Нюанс
|
||||
@msg `{id}` is not a colour adjustment `{id}` не е цветова корекция
|
||||
@msg missing `effect` липсва `effect`
|
||||
@msg `params` must be an object `params` трябва да бъде обект
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5738,3 +5738,20 @@ anchor Points: Punts:
|
||||
Simplify Anchors (Keep Shape) Simplifica els punts d’ancoratge (mantén la forma)
|
||||
Deep Ungroup Desagrupa tots els nivells
|
||||
Rejoin Path Pieces Torna a unir els trossos de traçat
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Efectes de color
|
||||
Color Effects Panel Tauler Efectes de color
|
||||
Exposure Exposició
|
||||
Exposure… Exposició…
|
||||
Desaturate Dessaturar
|
||||
Adjustment Ajust
|
||||
Add as Effect Afegeix com a efecte
|
||||
Apply as Filter Aplica com a filtre
|
||||
Select objects to adjust their colors. Seleccioneu objectes per ajustar-ne els colors.
|
||||
Brightness/Contrast Lluentor/Contrast
|
||||
Hue/Saturation To/saturació
|
||||
Temperature/Tint Temperatura/To
|
||||
@msg `{id}` is not a colour adjustment `{id}` no és un ajust de color
|
||||
@msg missing `effect` falta `effect`
|
||||
@msg `params` must be an object `params` ha de ser un objecte
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5747,3 +5747,20 @@ anchor Points: Body:
|
||||
Simplify Anchors (Keep Shape) Zjednodušit kotevní body (zachovat tvar)
|
||||
Deep Ungroup Oddělit všechny úrovně
|
||||
Rejoin Path Pieces Znovu spojit části cest
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Barevné efekty
|
||||
Color Effects Panel Panel Barevné efekty
|
||||
Exposure Expozice
|
||||
Exposure… Expozice…
|
||||
Desaturate Odbarvit
|
||||
Adjustment Úprava
|
||||
Add as Effect Přidat jako efekt
|
||||
Apply as Filter Použít jako filtr
|
||||
Select objects to adjust their colors. Vyberte objekty, jejichž barvy chcete upravit.
|
||||
Brightness/Contrast Jas/kontrast
|
||||
Hue/Saturation Odstín/sytost
|
||||
Temperature/Tint Teplota/nádech
|
||||
@msg `{id}` is not a colour adjustment `{id}` není úprava barev
|
||||
@msg missing `effect` chybí `effect`
|
||||
@msg `params` must be an object `params` musí být objekt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5652,3 +5652,20 @@ anchor Points: Punkter:
|
||||
Simplify Anchors (Keep Shape) Forenkl ankerpunkter (bevar form)
|
||||
Deep Ungroup Afgruppér alle niveauer
|
||||
Rejoin Path Pieces Forbind kurvestykker igen
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Farveeffekter
|
||||
Color Effects Panel Panelet Farveeffekter
|
||||
Exposure Eksponering
|
||||
Exposure… Eksponering…
|
||||
Desaturate Afmæt
|
||||
Adjustment Justering
|
||||
Add as Effect Tilføj som effekt
|
||||
Apply as Filter Anvend som filter
|
||||
Select objects to adjust their colors. Markér objekter for at justere deres farver.
|
||||
Brightness/Contrast Lysstyrke/kontrast
|
||||
Hue/Saturation Farvetone/mætning
|
||||
Temperature/Tint Temperatur/toning
|
||||
@msg `{id}` is not a colour adjustment `{id}` er ikke en farvejustering
|
||||
@msg missing `effect` `effect` mangler
|
||||
@msg `params` must be an object `params` skal være et objekt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5329,3 +5329,20 @@ anchor Points: Punkte:
|
||||
Simplify Anchors (Keep Shape) Ankerpunkte vereinfachen (Form erhalten)
|
||||
Deep Ungroup Alle Gruppierungsebenen aufheben
|
||||
Rejoin Path Pieces Pfadstücke wieder zusammenfügen
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Farbeffekte
|
||||
Color Effects Panel Farbeffekte-Bedienfeld
|
||||
Exposure Belichtung
|
||||
Exposure… Belichtung…
|
||||
Desaturate Sättigung verringern
|
||||
Adjustment Korrektur
|
||||
Add as Effect Als Effekt hinzufügen
|
||||
Apply as Filter Als Filter anwenden
|
||||
Select objects to adjust their colors. Wählen Sie Objekte aus, um ihre Farben anzupassen.
|
||||
Brightness/Contrast Helligkeit/Kontrast
|
||||
Hue/Saturation Farbton/Sättigung
|
||||
Temperature/Tint Temperatur/Farbstich
|
||||
@msg `{id}` is not a colour adjustment `{id}` ist keine Farbkorrektur
|
||||
@msg missing `effect` `effect` fehlt
|
||||
@msg `params` must be an object `params` muss ein Objekt sein
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5699,3 +5699,20 @@ anchor Points: Σημεία:
|
||||
Simplify Anchors (Keep Shape) Απλοποίηση σημείων αγκύρωσης (διατήρηση σχήματος)
|
||||
Deep Ungroup Κατάργηση ομαδοποίησης σε όλα τα επίπεδα
|
||||
Rejoin Path Pieces Επανένωση τμημάτων διαδρομών
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Εφέ χρώματος
|
||||
Color Effects Panel Πλαίσιο Εφέ χρώματος
|
||||
Exposure Έκθεση
|
||||
Exposure… Έκθεση…
|
||||
Desaturate Αποκορεσμός
|
||||
Adjustment Διόρθωση
|
||||
Add as Effect Προσθήκη ως εφέ
|
||||
Apply as Filter Εφαρμογή ως φίλτρο
|
||||
Select objects to adjust their colors. Επιλέξτε αντικείμενα για να προσαρμόσετε τα χρώματά τους.
|
||||
Brightness/Contrast Φωτεινότητα/Αντίθεση
|
||||
Hue/Saturation Απόχρωση/Κορεσμός
|
||||
Temperature/Tint Θερμοκρασία/Απόχρωση
|
||||
@msg `{id}` is not a colour adjustment Το `{id}` δεν είναι διόρθωση χρώματος
|
||||
@msg missing `effect` λείπει το `effect`
|
||||
@msg `params` must be an object Το `params` πρέπει να είναι αντικείμενο
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 164 and column 5.
|
@@ -5689,3 +5689,20 @@ anchor Points: Puntos:
|
||||
Simplify Anchors (Keep Shape) Simplificar puntos de ancla (mantener forma)
|
||||
Deep Ungroup Desagrupar todos los niveles
|
||||
Rejoin Path Pieces Volver a unir fragmentos de trazado
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Efectos de color
|
||||
Color Effects Panel Panel Efectos de color
|
||||
Exposure Exposición
|
||||
Exposure… Exposición…
|
||||
Desaturate Desaturar
|
||||
Adjustment Ajuste
|
||||
Add as Effect Añadir como efecto
|
||||
Apply as Filter Aplicar como filtro
|
||||
Select objects to adjust their colors. Seleccione objetos para ajustar sus colores.
|
||||
Brightness/Contrast Brillo/contraste
|
||||
Hue/Saturation Tono/saturación
|
||||
Temperature/Tint Temperatura/tinte
|
||||
@msg `{id}` is not a colour adjustment `{id}` no es un ajuste de color
|
||||
@msg missing `effect` falta `effect`
|
||||
@msg `params` must be an object `params` debe ser un objeto
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5778,3 +5778,20 @@ anchor Points: Pisteet:
|
||||
Simplify Anchors (Keep Shape) Yksinkertaista ankkuripisteet (säilytä muoto)
|
||||
Deep Ungroup Pura kaikki ryhmitystasot
|
||||
Rejoin Path Pieces Yhdistä polun palat uudelleen
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Väritehosteet
|
||||
Color Effects Panel Väritehosteet-paneeli
|
||||
Exposure Valotus
|
||||
Exposure… Valotus…
|
||||
Desaturate Poista värikylläisyys
|
||||
Adjustment Säätö
|
||||
Add as Effect Lisää tehosteena
|
||||
Apply as Filter Käytä suodattimena
|
||||
Select objects to adjust their colors. Valitse objektit, joiden värejä haluat säätää.
|
||||
Brightness/Contrast Kirkkaus/kontrasti
|
||||
Hue/Saturation Sävy/kylläisyys
|
||||
Temperature/Tint Lämpötila/sävy
|
||||
@msg `{id}` is not a colour adjustment `{id}` ei ole värisäätö
|
||||
@msg missing `effect` `effect` puuttuu
|
||||
@msg `params` must be an object `params` on oltava objekti
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5746,3 +5746,20 @@ anchor Points: Points :
|
||||
Simplify Anchors (Keep Shape) Simplifier les points d’ancrage (conserver la forme)
|
||||
Deep Ungroup Dissocier tous les niveaux
|
||||
Rejoin Path Pieces Rejoindre les morceaux de tracé
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Effets de couleur
|
||||
Color Effects Panel Panneau Effets de couleur
|
||||
Exposure Exposition
|
||||
Exposure… Exposition…
|
||||
Desaturate Désaturer
|
||||
Adjustment Réglage
|
||||
Add as Effect Ajouter comme effet
|
||||
Apply as Filter Appliquer comme filtre
|
||||
Select objects to adjust their colors. Sélectionnez des objets pour régler leurs couleurs.
|
||||
Brightness/Contrast Luminosité/contraste
|
||||
Hue/Saturation Teinte/saturation
|
||||
Temperature/Tint Température/teinte
|
||||
@msg `{id}` is not a colour adjustment `{id}` n'est pas un réglage de couleur
|
||||
@msg missing `effect` `effect` manquant
|
||||
@msg `params` must be an object `params` doit être un objet
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5733,3 +5733,20 @@ anchor Points: Pontok:
|
||||
Simplify Anchors (Keep Shape) Horgonypontok egyszerűsítése (alak megtartása)
|
||||
Deep Ungroup Csoportbontás minden szinten
|
||||
Rejoin Path Pieces Útvonaldarabok újraegyesítése
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Színeffektusok
|
||||
Color Effects Panel Színeffektusok panel
|
||||
Exposure Expozíció
|
||||
Exposure… Expozíció…
|
||||
Desaturate Telítettség csökkentése
|
||||
Adjustment Korrekció
|
||||
Add as Effect Hozzáadás effektusként
|
||||
Apply as Filter Alkalmazás szűrőként
|
||||
Select objects to adjust their colors. Jelöljön ki objektumokat a színeik módosításához.
|
||||
Brightness/Contrast Fényesség/kontraszt
|
||||
Hue/Saturation Színárnyalat/telítettség
|
||||
Temperature/Tint Színhőmérséklet/tónus
|
||||
@msg `{id}` is not a colour adjustment `{id}` nem színkorrekció
|
||||
@msg missing `effect` hiányzik: `effect`
|
||||
@msg `params` must be an object `params`: objektum kell
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5652,3 +5652,20 @@ anchor Points: Titik:
|
||||
Simplify Anchors (Keep Shape) Sederhanakan titik jangkar (pertahankan bentuk)
|
||||
Deep Ungroup Buka grup di semua tingkat
|
||||
Rejoin Path Pieces Sambungkan kembali potongan jalur
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Efek Warna
|
||||
Color Effects Panel Panel Efek Warna
|
||||
Exposure Eksposur
|
||||
Exposure… Eksposur…
|
||||
Desaturate Hilangkan Saturasi
|
||||
Adjustment Penyesuaian
|
||||
Add as Effect Tambahkan sebagai Efek
|
||||
Apply as Filter Terapkan sebagai Filter
|
||||
Select objects to adjust their colors. Pilih objek untuk menyesuaikan warnanya.
|
||||
Brightness/Contrast Kecerahan/kontras
|
||||
Hue/Saturation Rona/saturasi
|
||||
Temperature/Tint Suhu/tint
|
||||
@msg `{id}` is not a colour adjustment `{id}` bukan penyesuaian warna
|
||||
@msg missing `effect` `effect` tidak ada
|
||||
@msg `params` must be an object `params` harus berupa objek
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2169 and column 5.
|
@@ -5363,3 +5363,20 @@ anchor Points: Punti:
|
||||
Simplify Anchors (Keep Shape) Semplifica punti di ancoraggio (mantieni forma)
|
||||
Deep Ungroup Separa tutti i livelli
|
||||
Rejoin Path Pieces Ricongiungi parti di tracciato
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Effetti colore
|
||||
Color Effects Panel Pannello Effetti colore
|
||||
Exposure Esposizione
|
||||
Exposure… Esposizione…
|
||||
Desaturate Desatura
|
||||
Adjustment Regolazione
|
||||
Add as Effect Aggiungi come effetto
|
||||
Apply as Filter Applica come filtro
|
||||
Select objects to adjust their colors. Seleziona gli oggetti per regolarne i colori.
|
||||
Brightness/Contrast Luminosità/contrasto
|
||||
Hue/Saturation Tonalità/saturazione
|
||||
Temperature/Tint Temperatura/tinta
|
||||
@msg `{id}` is not a colour adjustment `{id}` non è una regolazione del colore
|
||||
@msg missing `effect` manca `effect`
|
||||
@msg `params` must be an object `params` deve essere un oggetto
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5432,3 +5432,20 @@ anchor Points: ポイント:
|
||||
Simplify Anchors (Keep Shape) アンカーポイントを単純化(形状を維持)
|
||||
Deep Ungroup すべての階層のグループ解除
|
||||
Rejoin Path Pieces パスの断片を再連結
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects カラー効果
|
||||
Color Effects Panel カラー効果パネル
|
||||
Exposure 露光量
|
||||
Exposure… 露光量…
|
||||
Desaturate 彩度を下げる
|
||||
Adjustment 補正
|
||||
Add as Effect 効果として追加
|
||||
Apply as Filter フィルターとして適用
|
||||
Select objects to adjust their colors. カラーを補正するオブジェクトを選択してください。
|
||||
Brightness/Contrast 明るさ・コントラスト
|
||||
Hue/Saturation 色相・彩度
|
||||
Temperature/Tint 色温度・色かぶり
|
||||
@msg `{id}` is not a colour adjustment `{id}` はカラー補正ではありません
|
||||
@msg missing `effect` `effect` が指定されていません
|
||||
@msg `params` must be an object `params` にはオブジェクトを指定してください
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5736,3 +5736,20 @@ anchor Points: წერტილები:
|
||||
Simplify Anchors (Keep Shape) საყრდენი წერტილების გამარტივება (ფორმის შენარჩუნებით)
|
||||
Deep Ungroup დაჯგუფების მოხსნა ყველა დონეზე
|
||||
Rejoin Path Pieces ტრაექტორიის ნაწილების ხელახლა შეერთება
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects ფერის ეფექტები
|
||||
Color Effects Panel ფერის ეფექტების პანელი
|
||||
Exposure ექსპოზიცია
|
||||
Exposure… ექსპოზიცია…
|
||||
Desaturate გაუფერულება
|
||||
Adjustment კორექცია
|
||||
Add as Effect ეფექტად დამატება
|
||||
Apply as Filter ფილტრად გამოყენება
|
||||
Select objects to adjust their colors. აირჩიეთ ობიექტები მათი ფერების დასარეგულირებლად.
|
||||
Brightness/Contrast სიკაშკაშე/კონტრასტი
|
||||
Hue/Saturation ფერის ტონი/გაჯერება
|
||||
Temperature/Tint ტემპერატურა/ტონირება
|
||||
@msg `{id}` is not a colour adjustment `{id}` ფერის კორექცია არ არის
|
||||
@msg missing `effect` აკლია `effect`
|
||||
@msg `params` must be an object `params` უნდა იყოს ობიექტი
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5326,3 +5326,20 @@ anchor Points: 포인트:
|
||||
Simplify Anchors (Keep Shape) 앵커 포인트 단순화(모양 유지)
|
||||
Deep Ungroup 모든 단계 그룹 해제
|
||||
Rejoin Path Pieces 패스 조각 다시 연결
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects 색상 효과
|
||||
Color Effects Panel 색상 효과 패널
|
||||
Exposure 노출
|
||||
Exposure… 노출…
|
||||
Desaturate 채도 감소
|
||||
Adjustment 조정
|
||||
Add as Effect 효과로 추가
|
||||
Apply as Filter 필터로 적용
|
||||
Select objects to adjust their colors. 색상을 조정할 개체를 선택하십시오.
|
||||
Brightness/Contrast 밝기/대비
|
||||
Hue/Saturation 색조/채도
|
||||
Temperature/Tint 색온도/색조
|
||||
@msg `{id}` is not a colour adjustment `{id}`은(는) 색상 조정이 아닙니다
|
||||
@msg missing `effect` `effect`이 없습니다
|
||||
@msg `params` must be an object `params`는 개체여야 합니다
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5696,3 +5696,20 @@ anchor Points: Punten:
|
||||
Simplify Anchors (Keep Shape) Ankerpunten vereenvoudigen (vorm behouden)
|
||||
Deep Ungroup Alle groeperingsniveaus opheffen
|
||||
Rejoin Path Pieces Padstukken opnieuw verbinden
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Kleureffecten
|
||||
Color Effects Panel Deelvenster Kleureffecten
|
||||
Exposure Belichting
|
||||
Exposure… Belichting…
|
||||
Desaturate Desatureren
|
||||
Adjustment Aanpassing
|
||||
Add as Effect Toevoegen als effect
|
||||
Apply as Filter Toepassen als filter
|
||||
Select objects to adjust their colors. Selecteer objecten om hun kleuren aan te passen.
|
||||
Brightness/Contrast Helderheid/contrast
|
||||
Hue/Saturation Kleurtoon/verzadiging
|
||||
Temperature/Tint Temperatuur/tint
|
||||
@msg `{id}` is not a colour adjustment `{id}` is geen kleuraanpassing
|
||||
@msg missing `effect` `effect` ontbreekt
|
||||
@msg `params` must be an object `params` moet een object zijn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5601,3 +5601,20 @@ anchor Points: Punkty:
|
||||
Simplify Anchors (Keep Shape) Uprość punkty kontrolne (zachowaj kształt)
|
||||
Deep Ungroup Rozgrupuj wszystkie poziomy
|
||||
Rejoin Path Pieces Ponownie połącz fragmenty ścieżek
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Efekty koloru
|
||||
Color Effects Panel Panel Efekty koloru
|
||||
Exposure Ekspozycja
|
||||
Exposure… Ekspozycja…
|
||||
Desaturate Usuń nasycenie
|
||||
Adjustment Korekta
|
||||
Add as Effect Dodaj jako efekt
|
||||
Apply as Filter Zastosuj jako filtr
|
||||
Select objects to adjust their colors. Zaznacz obiekty, aby skorygować ich kolory.
|
||||
Brightness/Contrast Jasność/kontrast
|
||||
Hue/Saturation Barwa/nasycenie
|
||||
Temperature/Tint Temperatura/odcień
|
||||
@msg `{id}` is not a colour adjustment `{id}` nie jest korektą koloru
|
||||
@msg missing `effect` brak `effect`
|
||||
@msg `params` must be an object `params` musi być obiektem
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5664,3 +5664,20 @@ anchor Points: Pontos:
|
||||
Simplify Anchors (Keep Shape) Simplificar Pontos de Ancoragem (Manter Forma)
|
||||
Deep Ungroup Desagrupar Todos os Níveis
|
||||
Rejoin Path Pieces Reunir Partes de Caminho
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Efeitos de cor
|
||||
Color Effects Panel Painel Efeitos de cor
|
||||
Exposure Exposição
|
||||
Exposure… Exposição…
|
||||
Desaturate Dessaturar
|
||||
Adjustment Ajuste
|
||||
Add as Effect Adicionar como efeito
|
||||
Apply as Filter Aplicar como filtro
|
||||
Select objects to adjust their colors. Selecione objetos para ajustar suas cores.
|
||||
Brightness/Contrast Brilho/Contraste
|
||||
Hue/Saturation Matiz/Saturação
|
||||
Temperature/Tint Temperatura/Tom
|
||||
@msg `{id}` is not a colour adjustment `{id}` não é um ajuste de cor
|
||||
@msg missing `effect` falta `effect`
|
||||
@msg `params` must be an object `params` deve ser um objeto
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -5725,3 +5725,20 @@ anchor Points: Точки:
|
||||
Simplify Anchors (Keep Shape) Упростить опорные точки (сохранить форму)
|
||||
Deep Ungroup Разгруппировать все уровни
|
||||
Rejoin Path Pieces Соединить части контуров
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Цветовые эффекты
|
||||
Color Effects Panel Панель «Цветовые эффекты»
|
||||
Exposure Экспозиция
|
||||
Exposure… Экспозиция…
|
||||
Desaturate Обесцветить
|
||||
Adjustment Коррекция
|
||||
Add as Effect Добавить как эффект
|
||||
Apply as Filter Применить как фильтр
|
||||
Select objects to adjust their colors. Выделите объекты, чтобы настроить их цвета.
|
||||
Brightness/Contrast Яркость/контраст
|
||||
Hue/Saturation Оттенок/насыщенность
|
||||
Temperature/Tint Температура/оттенок
|
||||
@msg `{id}` is not a colour adjustment `{id}` не является цветокоррекцией
|
||||
@msg missing `effect` отсутствует `effect`
|
||||
@msg `params` must be an object `params` должно быть объектом
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5771,3 +5771,20 @@ anchor Points: Punkter:
|
||||
Simplify Anchors (Keep Shape) Förenkla ankarpunkter (behåll formen)
|
||||
Deep Ungroup Dela upp grupper på alla nivåer
|
||||
Rejoin Path Pieces Foga samman banbitar igen
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Färgeffekter
|
||||
Color Effects Panel Panelen Färgeffekter
|
||||
Exposure Exponering
|
||||
Exposure… Exponering…
|
||||
Desaturate Avmätta
|
||||
Adjustment Justering
|
||||
Add as Effect Lägg till som effekt
|
||||
Apply as Filter Använd som filter
|
||||
Select objects to adjust their colors. Markera objekt för att justera deras färger.
|
||||
Brightness/Contrast Ljusstyrka/kontrast
|
||||
Hue/Saturation Nyans/mättnad
|
||||
Temperature/Tint Temperatur/färgton
|
||||
@msg `{id}` is not a colour adjustment `{id}` är ingen färgjustering
|
||||
@msg missing `effect` `effect` saknas
|
||||
@msg `params` must be an object `params` måste vara ett objekt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5705,3 +5705,20 @@ anchor Points: Noktalar:
|
||||
Simplify Anchors (Keep Shape) Bağlantı Noktalarını Basitleştir (Şekli Koru)
|
||||
Deep Ungroup Tüm Düzeylerde Grubu Çöz
|
||||
Rejoin Path Pieces Yol Parçalarını Yeniden Birleştir
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Renk Efektleri
|
||||
Color Effects Panel Renk Efektleri Paneli
|
||||
Exposure Pozlama
|
||||
Exposure… Pozlama…
|
||||
Desaturate Doygunluğu Kaldır
|
||||
Adjustment Ayar
|
||||
Add as Effect Efekt Olarak Ekle
|
||||
Apply as Filter Filtre Olarak Uygula
|
||||
Select objects to adjust their colors. Renklerini ayarlamak için nesneleri seçin.
|
||||
Brightness/Contrast Parlaklık/Kontrast
|
||||
Hue/Saturation Ton/Doygunluk
|
||||
Temperature/Tint Sıcaklık/Renk Tonu
|
||||
@msg `{id}` is not a colour adjustment `{id}` bir renk ayarı değil
|
||||
@msg missing `effect` "isim" eksik
|
||||
@msg `params` must be an object "gradyan" bir nesne olmalıdır
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5343,3 +5343,20 @@ anchor Points: Точки:
|
||||
Simplify Anchors (Keep Shape) Спростити опорні точки (зберегти форму)
|
||||
Deep Ungroup Розгрупувати всі рівні
|
||||
Rejoin Path Pieces З’єднати частини контурів
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Колірні ефекти
|
||||
Color Effects Panel Панель «Колірні ефекти»
|
||||
Exposure Експозиція
|
||||
Exposure… Експозиція…
|
||||
Desaturate Знебарвити
|
||||
Adjustment Корекція
|
||||
Add as Effect Додати як ефект
|
||||
Apply as Filter Застосувати як фільтр
|
||||
Select objects to adjust their colors. Виділіть об’єкти, щоб налаштувати їхні кольори.
|
||||
Brightness/Contrast Яскравість/контраст
|
||||
Hue/Saturation Відтінок/насиченість
|
||||
Temperature/Tint Температура/відтінок
|
||||
@msg `{id}` is not a colour adjustment `{id}` не є корекцією кольору
|
||||
@msg missing `effect` відсутня `effect`
|
||||
@msg `params` must be an object `params` має бути об’єктом
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 178 and column 5.
|
@@ -5345,3 +5345,20 @@ anchor Points: Điểm:
|
||||
Simplify Anchors (Keep Shape) Đơn giản hóa điểm neo (giữ hình dạng)
|
||||
Deep Ungroup Bỏ nhóm mọi cấp
|
||||
Rejoin Path Pieces Nối lại các mảnh đường dẫn
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects Hiệu ứng màu
|
||||
Color Effects Panel Bảng Hiệu ứng màu
|
||||
Exposure Phơi sáng
|
||||
Exposure… Phơi sáng…
|
||||
Desaturate Khử bão hòa
|
||||
Adjustment Điều chỉnh
|
||||
Add as Effect Thêm làm hiệu ứng
|
||||
Apply as Filter Áp dụng làm bộ lọc
|
||||
Select objects to adjust their colors. Chọn đối tượng để điều chỉnh màu của chúng.
|
||||
Brightness/Contrast Độ sáng/Tương phản
|
||||
Hue/Saturation Sắc độ/Độ bão hòa
|
||||
Temperature/Tint Nhiệt độ màu/Tông
|
||||
@msg `{id}` is not a colour adjustment `{id}` không phải là điều chỉnh màu
|
||||
@msg missing `effect` thiếu `effect`
|
||||
@msg `params` must be an object `params` phải là một đối tượng
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 200 and column 5.
|
@@ -5586,3 +5586,20 @@ anchor Points: 点:
|
||||
Simplify Anchors (Keep Shape) 简化锚点(保持形状)
|
||||
Deep Ungroup 取消所有层级编组
|
||||
Rejoin Path Pieces 重新连接路径片段
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects 颜色效果
|
||||
Color Effects Panel 颜色效果面板
|
||||
Exposure 曝光度
|
||||
Exposure… 曝光度…
|
||||
Desaturate 去色
|
||||
Adjustment 调整
|
||||
Add as Effect 添加为效果
|
||||
Apply as Filter 作为滤镜应用
|
||||
Select objects to adjust their colors. 选择对象以调整其颜色。
|
||||
Brightness/Contrast 亮度/对比
|
||||
Hue/Saturation 色相/饱和度
|
||||
Temperature/Tint 色温/色调
|
||||
@msg `{id}` is not a colour adjustment `{id}` 不是颜色调整
|
||||
@msg missing `effect` 缺少 `effect`
|
||||
@msg `params` must be an object `params` 必须是对象
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5382,3 +5382,20 @@ anchor Points: 點:
|
||||
Simplify Anchors (Keep Shape) 簡化錨點(保持形狀)
|
||||
Deep Ungroup 解散所有層級群組
|
||||
Rejoin Path Pieces 重新連接路徑片段
|
||||
|
||||
# Color Effects add-on (Object › Plug-ins › Color Effects, Effect › Color Effects): its effects, panel and messages.
|
||||
Color Effects 顏色效果
|
||||
Color Effects Panel 顏色效果面板
|
||||
Exposure 曝光度
|
||||
Exposure… 曝光度…
|
||||
Desaturate 去除飽和度
|
||||
Adjustment 調整
|
||||
Add as Effect 加入為效果
|
||||
Apply as Filter 套用為濾鏡
|
||||
Select objects to adjust their colors. 選取物件以調整其顏色。
|
||||
Brightness/Contrast 亮度/對比
|
||||
Hue/Saturation 色相/飽和度
|
||||
Temperature/Tint 色溫/色調
|
||||
@msg `{id}` is not a colour adjustment `{id}` 不是顏色調整
|
||||
@msg missing `effect` 未提供 `effect`
|
||||
@msg `params` must be an object `params` 必須是物件
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -134,6 +134,7 @@ pub(super) fn effect_menu() -> Vec<Item> {
|
||||
let order = [
|
||||
"3D and Materials",
|
||||
"Color Adjustments",
|
||||
"Color Effects",
|
||||
"Convert to Shape",
|
||||
"Crop Marks",
|
||||
"Distort & Transform",
|
||||
|
||||
@@ -180,6 +180,7 @@ pub fn show_icon_panel(app: &mut VectorcraftApp, ui: &mut Ui, id: &str) {
|
||||
asset_export::ID => asset_export::show(app, ui),
|
||||
css_properties::ID => css_properties::show(app, ui),
|
||||
crate::addons::cleanup::ID => crate::addons::cleanup::show(app, ui),
|
||||
crate::addons::color::ID => crate::addons::color::show(app, ui),
|
||||
id if library_panel::parse(id).is_some() => library_panel::show(app, ui, id),
|
||||
_ => {
|
||||
dim_label(ui, tl!("This panel is on the roadmap (see the parity plan)."));
|
||||
|
||||
@@ -198,6 +198,7 @@ pub const ICON_PANELS: &[(&str, &str, &str)] = &[
|
||||
(crate::panels::css_properties::ID, "CSS Properties", "globe"),
|
||||
(crate::panels::variables::ID, "Variables", "chart-column"),
|
||||
(crate::addons::cleanup::ID, "Artwork Cleanup", "sparkles"),
|
||||
(crate::addons::color::ID, "Color Effects", "sun"),
|
||||
];
|
||||
|
||||
/// Groups of icon panels separated by dividers in the collapsed column.
|
||||
|
||||
+28
@@ -5708,3 +5708,31 @@ topmost piece.
|
||||
{"name":"run_command","arguments":{"command":"addon.cleanup.fix","params":{"kinds":["strayPoints","needlessGroups"]}}}
|
||||
{"name":"run_command","arguments":{"command":"addon.cleanup.simplify","params":{"tolerance":40,"protectCorners":true}}}
|
||||
```
|
||||
|
||||
## Color Effects add-on
|
||||
|
||||
Color Effects is a built-in add-on: its effects are colour adjustments in Effect › Color Effects, its command is
|
||||
`addon.color.filter`, and in the desktop app it also lives in Object › Plug-ins › Color Effects and in its panel
|
||||
(`window.panel {panel: "colorEffects"}`).
|
||||
|
||||
Its live effects go on through `effect.apply` like any other and recolour what the object paints, in stack order with
|
||||
the other colour adjustments (Effect › Color Adjustments); each colour keeps its colour model:
|
||||
|
||||
| Effect | Parameters | Does |
|
||||
|---|---|---|
|
||||
| `addon.color.exposure` (Exposure…) | `exposure` stops −20…20 (0), `offset` −0.5…0.5 (0), `gamma` 0.1…10 (1) | Scales the light in linear light (each stop doubles or halves it, mostly in the highlights), adds the offset (shadows and midtones) and applies the gamma |
|
||||
| `addon.color.desaturate` (Desaturate) | none | Turns every colour to the grey of its lightness |
|
||||
| `addon.color.invert` (Invert Colors) | none | Turns every colour to its RGB inverse |
|
||||
|
||||
`addon.color.filter {effect, params?, fill?, stroke?, includeImages?, includePatterns?, ids?}` applies any colour
|
||||
adjustment, the add-on's or one of Effect › Color Adjustments', to the colours themselves instead of as a live effect:
|
||||
fills, strokes, type, gradient meshes, embedded images and pattern tiles, as `edit.colors.invert` reaches them, as one
|
||||
undo step. Missing `params` take the effect's dialog defaults; the objects' own effects stay as they are.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"effect.apply","params":{"effect":"addon.color.exposure","params":{"exposure":1.5}}}}
|
||||
{"name":"run_command","arguments":{"command":"addon.color.filter","params":{"effect":"adjust.hueSaturation","params":{"hue":120}}}}
|
||||
```
|
||||
|
||||
The panel picks an adjustment (Brightness/Contrast, Hue/Saturation, Levels, Temperature/Tint, Exposure, Desaturate or
|
||||
Invert Colors), sets its values, and then Add as Effect (`effect.apply`) or Apply as Filter (`addon.color.filter`).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Parity with Adobe Illustrator
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Artwork Cleanup, a built-in add-on beyond Illustrator; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Color Effects, a built-in add-on beyond Illustrator; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -1216,10 +1216,22 @@ Show, Fix Selected and Fix All (each one undo step), Deep Ungroup and Rejoin Pat
|
||||
alone; Fix All as one step; scopes; rejoin within the gap only) and `addons::cleanup::tests` in `vectorcraft-ui-egui`
|
||||
(the submenu opens the panel; Check lists what it finds). Commands: `docs/mcp.md` › Artwork Cleanup add-on.
|
||||
|
||||
## Color Effects add-on (2026-10-30)
|
||||
|
||||
A VectorCraft addition, not an Illustrator feature, so no area score moves. Effect › Color Effects adds live Exposure
|
||||
(stops of linear light, offset and gamma), Desaturate and Invert Colors as colour adjustments evaluated with those of
|
||||
Effect › Color Adjustments (`vectorcraft_effects::addons::color`), and `addon.color.filter` applies any colour adjustment
|
||||
to the colours themselves through the Edit Colors pass. Object › Plug-ins › Color Effects and its panel reach them.
|
||||
Tests: `addons::color` in `vectorcraft-effects` (exposure in stops, desaturate keeps lightness, invert twice is
|
||||
identity), `cmd::addons::color::tests` in `vectorcraft-engine` (drawn live without changing the colours; a filter as one
|
||||
undo step, with any adjustment and its params; bad requests refused) and `addons::color::tests` in
|
||||
`vectorcraft-ui-egui` (the menus and the panel). Commands: `docs/mcp.md` › Color Effects add-on.
|
||||
|
||||
## Revision history
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-30 | minor | Color Effects, a built-in add-on beyond Illustrator; scores and estimates unchanged |
|
||||
| 2026-10-30 | minor | Artwork Cleanup add-on (a VectorCraft addition): evidence added; scores unchanged. |
|
||||
| 2026-10-30 | minor | Hardware: a second finger cancels the tool press the first finger began, and a finger landing while another is down presses nothing, so a pinch only navigates (#4198); evidence added; scores unchanged (estimated). |
|
||||
| 2026-10-30 | minor | File formats: SVG export writes axis-aligned rectangles as `<rect>`, circles and ellipses as `<circle>`/`<ellipse>`, straight lines as `<line>` and other straight-segment paths as `<polygon>`/`<polyline>`, keeping `<path>` where a shape element would draw differently (#4652); evidence added; scores and hours unchanged (estimated). |
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
# UI and interaction parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Artwork Cleanup add-on: its panel and Object › Plug-ins submenu; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-30 · **Change:** minor (Color Effects add-on: its effects, panel and Object › Plug-ins submenu; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -322,6 +322,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Tabs panel: a stop drags from where the press landed, a stop just added included | done | #1458 |
|
||||
| Outline view keeps template layers in Preview, dimmed | done | #1486; a picture placed to be traced stays visible under the outlines |
|
||||
| Artwork Cleanup add-on (VectorCraft addition): Object › Plug-ins › Artwork Cleanup opens its panel, which checks the selection or the document for 16 kinds of issue, lists them with counts, and shows or fixes the picked rows or all of them, each fix one undo step; Simplify Anchors (Keep Shape), Rejoin Path Pieces and Deep Ungroup open their options first | done | `addon.cleanup.*`, `crates/ui-egui/src/addons/cleanup.rs` and its tests; not an Illustrator feature, so it is not scored |
|
||||
| Color Effects add-on (VectorCraft addition): live Exposure, Desaturate and Invert Colors in Effect › Color Effects and Object › Plug-ins › Color Effects; its panel picks a colour adjustment and its values and adds it as a live effect or applies it as a filter, into the colours, as one undo step | done | `addon.color.*`, `crates/ui-egui/src/addons/color.rs` and its tests; not an Illustrator feature, so it is not scored |
|
||||
|
||||
## Look and feel
|
||||
|
||||
@@ -362,6 +363,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-30 | minor | Color Effects add-on: its effects, panel and Object › Plug-ins submenu; scores and estimates unchanged |
|
||||
| 2026-10-30 | minor | Artwork Cleanup add-on (a VectorCraft addition): its panel and Object › Plug-ins › Artwork Cleanup; scores and estimates unchanged |
|
||||
| 2026-10-30 | minor | Spinners: a held arrow repeats after a pause (#4267); scores and estimates unchanged |
|
||||
| 2026-10-30 | minor | Control bar: a Replace menu swaps the selected symbol instances' symbol (#4121); scores and estimates unchanged |
|
||||
|
||||
Reference in New Issue
Block a user