mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 00:10:11 +00:00
Since #2664, swatch.new separates an RGB color into CMYK through the color settings in a CMYK document unless keepModel is given. The Color Guide, Color Themes and Recolor Artwork send keepModel when they save colors they show, but the Color panel menu's Create New Swatch, the Swatches panel and the Gradient panel did not. An RGB object's color saved from them became a CMYK swatch, and a gradient's RGB stops became CMYK stops. These now send keepModel: Create New Swatch, an Alt-click on New Swatch, the New Swatch dialog for a gradient, a Fill or Stroke proxy or the Gradient panel's thumbnail dropped on the Swatches panel or Alt-dropped on a swatch of its kind, and the Gradient panel's Add to Swatches and Save to Swatches. A new swatch_paint_params returns paint_params with keepModel: true added for an unlinked color or a gradient. swatch.new without keepModel still converts RGB input. Docs: docs/target-app-parity.md.
104 lines
4.6 KiB
Rust
104 lines
4.6 KiB
Rust
//! New Swatch: the Swatch Options fields (name, colour type, Global, mode, sliders and hex)
|
|
//! prefilled from the active fill or stroke; a gradient, a pattern or a tint of a global colour
|
|
//! (saved as a tint swatch, "Name 40%") only takes a name. OK runs `swatch.new`.
|
|
//!
|
|
//! Fields: `name`, `spot`, `global`, `mode` and `color` as in Swatch Options, `group` (the colour
|
|
//! group the colour goes into; empty for none), `__paint` (the `swatch.new` paint of a gradient,
|
|
//! pattern or tint; absent for a colour) and `__auto` (the default name, which follows the colour until
|
|
//! the name is edited).
|
|
|
|
use serde_json::{Value, json};
|
|
use vectorcraft_color::Paint;
|
|
|
|
use super::swatch_options::{color_of, editor, grid, mode_id, name_row};
|
|
use super::{DialogSpec, run_and_close};
|
|
use crate::VectorcraftApp;
|
|
use crate::panels::color::Mode;
|
|
use crate::state::Dialog;
|
|
|
|
/// The dialog kind of New Swatch.
|
|
pub const KIND: &str = "newSwatch";
|
|
|
|
pub(super) const SPEC: DialogSpec = DialogSpec { heading: |_| tl!("New Swatch").into(), body, confirm, min_width: 340.0, ..DialogSpec::FORM };
|
|
|
|
/// Open New Swatch for the active paint, going into color `group`. A color opens as a spot color
|
|
/// with `spot`, and as a global process color with `global` alone.
|
|
pub fn open(app: &mut VectorcraftApp, spot: bool, global: bool, group: Option<&str>) -> Result<Value, String> {
|
|
let paint = crate::panels::active_paint(app);
|
|
let name = app.session.active().ok_or("no document open")?.doc.new_swatch_name(&paint);
|
|
let mut fields = match &paint {
|
|
Paint::Solid { swatch: Some(_), tint, .. } if *tint < 1.0 => {
|
|
json!({"__paint": crate::panels::paint_params(&paint), "group": group.unwrap_or_default()})
|
|
}
|
|
Paint::Solid { color, .. } => {
|
|
json!({"color": color, "mode": mode_id(Mode::of(color)), "spot": spot, "global": spot || global, "group": group.unwrap_or_default()})
|
|
}
|
|
Paint::None => return Err("pick a colour, gradient or pattern to save as a swatch".into()),
|
|
other => json!({"__paint": crate::panels::swatch_paint_params(other)}),
|
|
};
|
|
fields["name"] = json!(name);
|
|
fields["__auto"] = json!(name);
|
|
app.ui.dialog = Some(Dialog::new(KIND, fields));
|
|
Ok(Value::Null)
|
|
}
|
|
|
|
fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
|
if d.fields.contains_key("__paint") {
|
|
grid(ui, |ui| name_row(ui, d));
|
|
} else if editor(ui, d)
|
|
&& d.str("name") == d.str("__auto")
|
|
&& let Some(st) = app.session.active()
|
|
{
|
|
// The default name follows the colour until it is edited.
|
|
let auto = st.doc.new_swatch_name(&Paint::solid(color_of(d)));
|
|
d.fields.insert("name".into(), json!(auto));
|
|
d.fields.insert("__auto".into(), json!(auto));
|
|
}
|
|
false
|
|
}
|
|
|
|
/// `swatch.new` parameters from the fields.
|
|
fn params(d: &Dialog) -> Value {
|
|
let mut p = match d.fields.get("__paint") {
|
|
Some(paint) => paint.clone(),
|
|
None => json!({"color": color_of(d), "mode": d.str("mode"), "spot": d.bool("spot"), "global": d.bool("global")}),
|
|
};
|
|
p["name"] = json!(d.str("name"));
|
|
let group = d.str("group");
|
|
if !group.is_empty() {
|
|
p["group"] = json!(group);
|
|
}
|
|
p
|
|
}
|
|
|
|
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
|
run_and_close(app, "swatch.new", params(d))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn params_carry_the_colour_or_the_paint() {
|
|
let d = Dialog::new(KIND, json!({"name": "Sky", "color": "#2a6fb0", "mode": "rgb", "spot": true, "global": true, "group": "Mine"}));
|
|
assert_eq!(params(&d), json!({"name": "Sky", "color": color_of(&d), "mode": "rgb", "spot": true, "global": true, "group": "Mine"}));
|
|
let d = Dialog::new(KIND, json!({"name": "Dots", "__paint": {"pattern": "Dots"}, "group": ""}));
|
|
assert_eq!(params(&d), json!({"name": "Dots", "pattern": "Dots"}));
|
|
}
|
|
|
|
#[test]
|
|
fn a_tint_opens_as_a_named_tint_swatch() {
|
|
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
|
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
|
|
app.run("swatch.new", json!({"name": "Ink", "color": "#cc0066", "spot": true})).unwrap();
|
|
app.run("paint.setFill", json!({"swatch": "Ink", "tint": 40})).unwrap();
|
|
open(&mut app, false, false, None).unwrap();
|
|
let d = app.ui.dialog.clone().unwrap();
|
|
assert_eq!(params(&d), json!({"name": "Ink 40%", "swatch": "Ink", "tint": 40.0}));
|
|
run_and_close(&mut app, "swatch.new", params(&d)).unwrap();
|
|
let w = app.session.doc().unwrap().doc.swatch("Ink 40%").cloned().unwrap();
|
|
assert_eq!(w.tint_of(), Some(("Ink", 0.4)));
|
|
}
|
|
}
|