diff --git a/crates/ui-egui/src/dialogs/color_guide_options.rs b/crates/ui-egui/src/dialogs/color_guide_options.rs index faeb11e0d..1fe685e60 100644 --- a/crates/ui-egui/src/dialogs/color_guide_options.rs +++ b/crates/ui-egui/src/dialogs/color_guide_options.rs @@ -45,7 +45,7 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { ui.add_space(10.0); // Preview: the base colour's row of variations. let o = options(app, d); - let base = base_color(app, ui.ctx()); + let base = base_color(app); let n = o.steps as i32; let (row, _) = ui.allocate_exact_size(vec2(ui.available_width(), 22.0), Sense::hover()); let w = row.width() / (2 * n + 1) as f32; diff --git a/crates/ui-egui/src/dialogs/color_picker.rs b/crates/ui-egui/src/dialogs/color_picker.rs index eb72ae7bb..60c037597 100644 --- a/crates/ui-egui/src/dialogs/color_picker.rs +++ b/crates/ui-egui/src/dialogs/color_picker.rs @@ -3,7 +3,8 @@ //! the out-of-gamut and out-of-web warnings (click to correct); New/Original chips; an eyedropper //! button that samples a color anywhere on the screen ([`crate::screen_color`]); and a Color //! Swatches list. With art selected the colour shows on it live as it is picked; OK keeps it as one -//! undo step through `paint.setFill` / `paint.setStroke`, Cancel puts the art back. +//! undo step through `paint.setFill` / `paint.setStroke` and makes the color the Color Guide's +//! base color; Cancel puts the art back. //! Opened for an artboard (Properties › Artboards › Fill), it shows the color on the artboard's //! paper live, and OK keeps it as one undo step through `artboard.setProps {index, color}`. //! Opened over Recolor Artwork (double-click a row's new color), its OK sets that row's new color @@ -636,7 +637,13 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result { return Ok(Value::Null); } let (cmd, params) = paint_command(app, d); - super::form::commit_preview(app, cmd, params) + let c = in_document_model(app, picked(d).color); + let r = super::form::commit_preview(app, cmd, params)?; + // A color picked for the fill or stroke also becomes the Color Guide's base color. + if !d.fields.contains_key("artboard") { + crate::panels::color_guide::choose_base(app, c); + } + Ok(r) } #[cfg(test)] diff --git a/crates/ui-egui/src/dialogs/color_picker/tests.rs b/crates/ui-egui/src/dialogs/color_picker/tests.rs index cc650978b..4d678b106 100644 --- a/crates/ui-egui/src/dialogs/color_picker/tests.rs +++ b/crates/ui-egui/src/dialogs/color_picker/tests.rs @@ -275,6 +275,30 @@ fn open_set_hex_and_confirm_fills() { assert_eq!(crate::panels::current_paints(&app).0.color(), Some(Color::cmyk(0.0, 1.0, 1.0, 0.0))); } +/// OK makes the picked fill or stroke color the Color Guide's base color (#3137); Cancel and a +/// color picked for an artboard leave the base as it is. +#[test] +fn ok_makes_the_picked_color_the_color_guides_base() { + let mut app = app(); + let base = |app: &VectorcraftApp| crate::panels::color_guide::base_color(app).to_hex(); + app.ui.color_guide_base = Some(Color::WHITE); + app.run("ui.colorPicker", json!({})).unwrap(); + app.ui.dialog.as_mut().unwrap().fields.insert("hex".into(), json!("2050a0")); + super::super::confirm(&mut app).unwrap(); + assert_eq!(base(&app), "#2050a0"); + app.run("ui.colorPicker", json!({"stroke": true})).unwrap(); + app.ui.dialog.as_mut().unwrap().fields.insert("hex".into(), json!("a02050")); + frame(&mut app); + super::super::cancel(&mut app); + assert_eq!(base(&app), "#2050a0", "Cancel keeps the base"); + app.run("select.set", json!({"ids": []})).unwrap(); + app.run("artboard.new", json!({})).unwrap(); + app.run("ui.colorPicker", json!({"artboard": 1})).unwrap(); + app.ui.dialog.as_mut().unwrap().fields.insert("hex".into(), json!("00ff00")); + super::super::confirm(&mut app).unwrap(); + assert_eq!(base(&app), "#2050a0", "an artboard's color leaves the base"); +} + /// #1692: Tab goes through one color model's fields before the next: H, S, B, then R, G, B, the /// hex field, then L, a, b, then C, M, Y, K. Each Lab or CMYK field is level with the field on /// its left. diff --git a/crates/ui-egui/src/panels/color.rs b/crates/ui-egui/src/panels/color.rs index 8ef401c6f..f9567e988 100644 --- a/crates/ui-egui/src/panels/color.rs +++ b/crates/ui-egui/src/panels/color.rs @@ -432,6 +432,15 @@ fn apply(app: &mut VectorcraftApp, tgt: &Target, c: Color, phase: Live, behind: } } +/// [`apply`] a color chosen in the panel; once the pick ends, it also becomes the Color Guide's +/// base color. +fn choose(app: &mut VectorcraftApp, tgt: &Target, c: Color, phase: Live, behind: bool) { + if phase == Live::Released { + super::color_guide::choose_base(app, c); + } + apply(app, tgt, c, phase, behind); +} + /// Set the target's tint of its swatch to `t` (0..1), keeping the link (the T slider). fn apply_tint(app: &mut VectorcraftApp, tgt: &Target, tint: &Tint, t: f32, phase: Live) { match tgt { @@ -580,7 +589,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { }) .inner; match hit { - Some(SpectrumHit::Pick(c, phase)) => apply(app, &tgt, c, phase, alt), + Some(SpectrumHit::Pick(c, phase)) => choose(app, &tgt, c, phase, alt), Some(SpectrumHit::Cycle) => set_mode(app, &tgt, mode.next()), Some(SpectrumHit::Recolor { invert }) => recolor(app, ui, &tgt, invert, alt), None => {} @@ -718,15 +727,18 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { None => {} } if let Some((c, phase)) = behind { - apply(app, &tgt, c, phase, true); + choose(app, &tgt, c, phase, true); } if let (Some((t, phase)), Some(tint)) = (tinted, tgt.tint()) { + if phase == Live::Released { + super::color_guide::choose_base(app, tint.base.tinted(t)); + } apply_tint(app, &tgt, tint, t, phase); } if let Some((c, phase, comps2)) = new { let key = (c.to_hex(), mode as u8); set_pstate(ui.ctx(), "color-comps", Some((key, comps2))); - apply(app, &tgt, c, phase, false); + choose(app, &tgt, c, phase, false); } } diff --git a/crates/ui-egui/src/panels/color/tests.rs b/crates/ui-egui/src/panels/color/tests.rs index 20485020e..548851e6b 100644 --- a/crates/ui-egui/src/panels/color/tests.rs +++ b/crates/ui-egui/src/panels/color/tests.rs @@ -318,6 +318,22 @@ fn alt_click_on_the_spectrum_paints_the_stroke() { assert_eq!(paints_hex(&app).0, "#ff0000"); } +/// A color picked in the panel, for either proxy, becomes the Color Guide's base color (#3137). +#[test] +fn a_picked_color_becomes_the_color_guides_base() { + let mut app = app(); + let ctx = egui::Context::default(); + app.run("paint.setFill", json!({"color": "#ffffff"})).unwrap(); + app.ui.color_guide_base = Some(Color::WHITE); + click_spectrum(&mut app, &ctx, (0.0, 0.5), egui::Modifiers::NONE); + assert_eq!(crate::panels::color_guide::base_color(&app).to_hex(), "#ff0000"); + // Alt: the stroke takes it, and it is still the base. + click_spectrum(&mut app, &ctx, (0.5, 0.5), egui::Modifiers::ALT); + let stroke = paints_hex(&app).1; + assert_ne!(stroke, "#ff0000"); + assert_eq!(crate::panels::color_guide::base_color(&app).to_hex(), stroke); +} + #[test] fn shift_click_on_the_spectrum_cycles_modes() { let mut app = app(); diff --git a/crates/ui-egui/src/panels/color_guide.rs b/crates/ui-egui/src/panels/color_guide.rs index aa19103ce..28534e443 100644 --- a/crates/ui-egui/src/panels/color_guide.rs +++ b/crates/ui-egui/src/panels/color_guide.rs @@ -1,8 +1,11 @@ //! Color Guide panel: the base colour, the harmony-rule dropdown with the harmony strip, and the //! variation grid: a row per harmony colour with the colour itself in the centre column, //! shades/cool/muted to the left and tints/warm/vivid to the right (steps and reach from Color -//! Guide Options). The base colour stays put until "Set base color" takes the current colour. A -//! click on a cell applies it to the active proxy and selects it; Shift- or Cmd/Ctrl-click adds +//! Guide Options). The base color is the color last chosen in the Color panel, the Swatches panel +//! or the Color Picker ([`choose_base`]); selecting artwork leaves it as it is, and the base chip +//! ("Set base color to the current color") takes the current color, such as a cell applied from +//! the guide or the selected artwork's color. A click on a cell applies it to the active proxy, +//! without changing the base, and selects it; Shift- or Cmd/Ctrl-click adds //! cells to the selection that Save Colors as Swatches saves. Limit to Library (the library button, //! `ui.colorGuideLimit`) snaps every colour to a swatch library or the document's swatches; Edit or //! Apply Colors opens Recolor Artwork with the harmony colours, limited the same way. @@ -21,14 +24,16 @@ use crate::widgets::{self, menu_item}; /// The base colour before one is set: an orange. const DEFAULT_BASE: Color = Color::Rgb { r: 230.0 / 255.0, g: 120.0 / 255.0, b: 40.0 / 255.0 }; -/// The guide's base colour: fixed once set; the current colour when the panel first shows. -pub(crate) fn base_color(app: &VectorcraftApp, ctx: &egui::Context) -> Color { - if let Some(c) = pstate::>(ctx, "cg-base") { - return c; - } - let c = active_paint(app).color().unwrap_or(DEFAULT_BASE); - set_pstate(ctx, "cg-base", Some(c)); - c +/// The guide's base color: the one last chosen or set with the base chip; before that, the current +/// color. +pub(crate) fn base_color(app: &VectorcraftApp) -> Color { + app.ui.color_guide_base.unwrap_or_else(|| active_paint(app).color().unwrap_or(DEFAULT_BASE)) +} + +/// Make `c` the guide's base color: a color chosen in the Color panel, the Swatches panel or the +/// Color Picker. A color applied from the guide itself leaves the base as it is. +pub(crate) fn choose_base(app: &mut VectorcraftApp, c: Color) { + app.ui.color_guide_base = Some(c); } fn rule(ctx: &egui::Context) -> Harmony { @@ -59,7 +64,7 @@ struct GuideKey { /// The guide the panel shows, limited to the Limit to Library colours. fn guide(app: &VectorcraftApp, ctx: &egui::Context) -> Guide { - let (base, rule, opts) = (base_color(app, ctx), rule(ctx), app.ui.color_guide); + let (base, rule, opts) = (base_color(app), rule(ctx), app.ui.color_guide); let limit = &app.ui.color_guide_limit; if limit.is_empty() { return Guide::new(base, rule, &opts); @@ -132,6 +137,15 @@ fn save_selected(app: &mut VectorcraftApp, ctx: &egui::Context) { pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { let t = crate::theme::Tokens::get(ui.ctx()); let ctx = ui.ctx().clone(); + // The current color becomes the base when the panel first shows; selecting artwork later + // leaves it as it is. + let first = base_color(app); + let set = *app.ui.color_guide_base.get_or_insert(first); + // Selected cells belong to the guide they were picked from: a new base clears them. + if pstate::>(&ctx, "cg-sel-base") != Some(set) { + set_pstate(&ctx, "cg-sel-base", Some(set)); + clear_selection(&ctx); + } let h = rule(&ctx); let g = guide(app, &ctx); let base = g.colors[0]; @@ -142,7 +156,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { if resp.on_hover_text(tl!("Set base color to the current color")).clicked() && let Some(c) = active_paint(app).color() { - set_pstate(&ctx, "cg-base", Some(c)); + app.ui.color_guide_base = Some(c); clear_selection(&ctx); } let labels: Vec<&str> = Harmony::ALL.iter().map(|h| h.label()).collect(); @@ -294,22 +308,83 @@ mod tests { assert_eq!(role_and_state(&shown, "Limit colors to swatch library: Earth Tones"), (Role::Button, Some(Toggled::True))); } + /// The first show takes the current color; a color chosen in the Color panel, Swatches or the + /// Color Picker becomes the base; selecting artwork with another color leaves it. #[test] - fn base_stays_until_set_and_the_grid_follows_the_options() { + fn a_chosen_color_becomes_the_base_and_selecting_art_keeps_it() { let mut app = app(); + let red = app.run("shape.rectangle", json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap()["id"].clone(); + app.run("paint.setFill", json!({"color": "#ff0000"})).unwrap(); + let blue = app.run("shape.rectangle", json!({"x": 20, "y": 0, "width": 10, "height": 10})).unwrap()["id"].clone(); app.run("paint.setFill", json!({"color": "#3366cc"})).unwrap(); let ctx = egui::Context::default(); frame(&mut app, &ctx); - assert_eq!(base_color(&app, &ctx).to_hex(), "#3366cc", "the first show takes the current colour"); - // Another current colour leaves the base alone. - app.run("paint.setFill", json!({"color": "#ff0000"})).unwrap(); + assert_eq!(base_color(&app).to_hex(), "#3366cc", "the first show takes the current color"); + app.run("select.set", json!({"ids": [red]})).unwrap(); + frame(&mut app, &ctx); + assert_eq!(base_color(&app).to_hex(), "#3366cc", "selecting art keeps the base"); + choose_base(&mut app, Color::from_hex("#20a060").unwrap()); frame(&mut app, &ctx); - assert_eq!(base_color(&app, &ctx).to_hex(), "#3366cc"); app.ui.color_guide.steps = 6; frame(&mut app, &ctx); let g = guide(&app, &ctx); assert_eq!(g.grid[0].len(), 13); - assert_eq!(g.grid[0][6].to_hex(), "#3366cc", "the base sits in the centre of the first row"); + assert_eq!(g.grid[0][6].to_hex(), "#20a060", "the chosen base sits in the centre of the first row"); + app.run("select.set", json!({"ids": [blue]})).unwrap(); + frame(&mut app, &ctx); + assert_eq!(base_color(&app).to_hex(), "#20a060"); + } + + /// The rect of the panel widget `id` after one frame. + fn rect_of(app: &mut VectorcraftApp, ctx: &egui::Context, id: impl std::hash::Hash + std::fmt::Debug) -> Rect { + let mut r = None; + let mut out = ctx.run_ui(egui::RawInput::default(), |ui| { + show(app, ui); + r = ctx.read_response(ui.scope_id().with(&id)).map(|r| r.rect); + }); + out.textures_delta.clear(); + r.expect("the widget is drawn") + } + + fn click(app: &mut VectorcraftApp, ctx: &egui::Context, at: egui::Pos2) { + let button = + |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: egui::Modifiers::NONE }; + for events in [vec![egui::Event::PointerMoved(at), button(true)], vec![button(false)]] { + let mut out = ctx.run_ui(egui::RawInput { events, ..Default::default() }, |ui| show(app, ui)); + out.textures_delta.clear(); + } + } + + /// A harmony color or a variation clicked in the guide paints the art without changing the + /// base; the base chip then makes the current color the base. + #[test] + fn a_guide_color_applies_without_moving_the_base_until_set_as_base() { + let mut app = app(); + app.run("shape.rectangle", json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap(); + app.run("paint.setFill", json!({"color": "#3366cc"})).unwrap(); + let ctx = egui::Context::default(); + frame(&mut app, &ctx); + let g = guide(&app, &ctx); + let fill = |app: &VectorcraftApp| crate::panels::current_paints(app).0.color().map(|c| c.to_hex()); + let at = rect_of(&mut app, &ctx, ("cg-h", 1)).center(); + click(&mut app, &ctx, at); + assert_eq!(fill(&app), Some(g.colors[1].to_hex()), "the harmony color paints the art"); + assert_eq!(base_color(&app).to_hex(), "#3366cc", "and leaves the base"); + let at = rect_of(&mut app, &ctx, ("cg-v", 0usize, 2usize)).center(); + click(&mut app, &ctx, at); + let variation = g.grid[0][2].to_hex(); + assert_eq!(fill(&app), Some(variation.clone()), "a variation paints the art"); + assert_eq!(base_color(&app).to_hex(), "#3366cc"); + assert_eq!(guide(&app, &ctx).grid, g.grid, "the guide stays as it was"); + // Set base color to the current color: the applied variation becomes the base. + let mut chip = None; + let mut out = ctx.run_ui(egui::RawInput::default(), |ui| { + show(&mut app, ui); + chip = Some(ui.min_rect().left_top() + egui::vec2(8.0, 8.0)); + }); + out.textures_delta.clear(); + click(&mut app, &ctx, chip.expect("the panel is drawn")); + assert_eq!(base_color(&app).to_hex(), variation, "the base chip adopts the current color"); } #[test] diff --git a/crates/ui-egui/src/panels/library_panel/tests.rs b/crates/ui-egui/src/panels/library_panel/tests.rs index 9e1db24a8..f908dbd9d 100644 --- a/crates/ui-egui/src/panels/library_panel/tests.rs +++ b/crates/ui-egui/src/panels/library_panel/tests.rs @@ -70,6 +70,18 @@ fn clicking_a_library_swatch_adds_and_applies_it_in_one_step() { assert!(last_open(&app.ui).is_none()); } +/// A color clicked in a swatch library becomes the Color Guide's base color (#3137). +#[test] +fn a_clicked_library_color_becomes_the_color_guides_base() { + let mut app = app(); + let ctx = context(); + app.run("window.swatchLibrary", json!({"library": "pastels"})).unwrap(); + app.ui.color_guide_base = Some(vectorcraft_color::Color::WHITE); + click(&mut app, &ctx, "Pastel Teal", Modifiers::NONE, 0.0); + let teal = app.session.doc().unwrap().doc.swatch("Pastel Teal").and_then(|w| w.paint.color()).unwrap(); + assert_eq!(crate::panels::color_guide::base_color(&app), teal); +} + #[test] fn modifier_clicks_select_and_add_to_swatches_adds_the_selection() { let mut app = app(); diff --git a/crates/ui-egui/src/panels/swatches.rs b/crates/ui-egui/src/panels/swatches.rs index 34262e71c..2dd054f39 100644 --- a/crates/ui-egui/src/panels/swatches.rs +++ b/crates/ui-egui/src/panels/swatches.rs @@ -187,9 +187,15 @@ fn swatch_params(e: &Entry) -> Option { /// Apply a clicked swatch to the active proxy (Alt: the inactive one). An Alt-click on a color /// swatch with a gradient stop selected recolors the stop as dropping the swatch on it does, -/// and with a freeform gradient point selected it recolors the point. +/// and with a freeform gradient point selected it recolors the point. A color swatch also becomes +/// the Color Guide's base color. fn apply(app: &mut VectorcraftApp, ui: &Ui, e: &Entry) { let Some(params) = swatch_params(e) else { return }; + if let Entry::Swatch { paint, .. } = e + && let Some(c) = paint.color() + { + super::color_guide::choose_base(app, c); + } if super::alt_held(ui) && let Some(c) = drag_of(e, vec![]).color() && super::gradient::recolor_selected(app, c, ¶ms) diff --git a/crates/ui-egui/src/panels/swatches/body.rs b/crates/ui-egui/src/panels/swatches/body.rs index 7f9c5d296..9147960ba 100644 --- a/crates/ui-egui/src/panels/swatches/body.rs +++ b/crates/ui-egui/src/panels/swatches/body.rs @@ -30,8 +30,10 @@ pub(super) fn body(app: &mut VectorcraftApp, ui: &mut Ui, salt: &'static str) { } }); ui.add_space(4.0); - // A recent colour paints the active proxy (Alt: the inactive one), as a swatch does. + // A recent colour paints the active proxy (Alt: the inactive one), as a swatch does, and + // becomes the Color Guide's base color. if let Some(c) = crate::panels::recent_colors_row(app, ui) { + crate::panels::color_guide::choose_base(app, c); crate::panels::apply_click(app, ui, json!({"color": crate::panels::color_json(&c)})); } widgets::divider(ui); diff --git a/crates/ui-egui/src/panels/swatches/libraries.rs b/crates/ui-egui/src/panels/swatches/libraries.rs index 02f149987..f5b4d4fb6 100644 --- a/crates/ui-egui/src/panels/swatches/libraries.rs +++ b/crates/ui-egui/src/panels/swatches/libraries.rs @@ -91,8 +91,12 @@ impl LibraryKind for SwatchLibraries { fn describe(w: &Swatch) -> String { describe(&w.paint, w.global, w.spot) } - /// Adds the swatch and applies it to the active proxy (Alt: the inactive one), as one step. + /// Adds the swatch and applies it to the active proxy (Alt: the inactive one), as one step. A + /// color swatch also becomes the Color Guide's base color. fn click(app: &mut VectorcraftApp, ui: &Ui, id: &str, name: &str) { + if let Some(c) = swatchlib::library(&app.session, id).and_then(|(_, lib)| lib.iter().find(|w| w.name == name).and_then(|w| w.paint.color())) { + crate::panels::color_guide::choose_base(app, c); + } let alt = crate::panels::alt_held(ui); let apply = if crate::panels::proxy_cmd(app, alt) == "paint.setFill" { "fill" } else { "stroke" }; add_from_library(app, json!({"library": id, "names": [name], "apply": apply, "focus": !alt})); diff --git a/crates/ui-egui/src/panels/swatches/tests.rs b/crates/ui-egui/src/panels/swatches/tests.rs index 4175ed0cb..7d751fe9d 100644 --- a/crates/ui-egui/src/panels/swatches/tests.rs +++ b/crates/ui-egui/src/panels/swatches/tests.rs @@ -133,6 +133,34 @@ fn modifier_clicks_select_several_swatches_and_groups() { assert_eq!(selected(&ctx), ["Grays"], "a plain click on a group selects it alone"); } +/// A color swatch or a recent color clicked in the panel becomes the Color Guide's base color +/// (#3137); a modifier click only selects. +#[test] +fn a_clicked_color_swatch_becomes_the_color_guides_base() { + let mut app = app(); + let ctx = context(); + app.ui.color_guide_base = Some(Color::WHITE); + click_tile(&mut app, &ctx, "Red", Modifiers::NONE, 0.0); + let base = |app: &VectorcraftApp| crate::panels::color_guide::base_color(app).to_hex(); + assert_eq!(base(&app), "#ed1c24"); + click_tile(&mut app, &ctx, "Amber", Modifiers::SHIFT, 2.0); + assert_eq!(base(&app), "#ed1c24", "a modifier click only selects"); + // A recent color: the panel's first recent chip. + app.run("paint.setFill", json!({"color": "#2050a0"})).unwrap(); + app.ui.color_guide_base = Some(Color::WHITE); + let mut chip = None; + let screen_rect = Some(Rect::from_min_size(Pos2::ZERO, vec2(280.0, 700.0))); + let mut out = ctx.run_ui(egui::RawInput { time: Some(4.0), screen_rect, ..Default::default() }, |ui| { + show(&mut app, ui); + chip = ctx.read_response(ui.scope_id().with(("recent", 0usize))).map(|r| r.rect.center()); + }); + out.textures_delta.clear(); + let at = chip.expect("the recent chip is drawn"); + let button = |pressed| Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE }; + frame(&mut app, &ctx, vec![Event::PointerMoved(at), button(true), button(false)], 5.0, show); + assert_eq!(base(&app), "#2050a0"); +} + /// The hex colors of the stops of the selection's gradient fill, and its stroke's color. fn stops_and_stroke(app: &VectorcraftApp) -> (Vec, String) { let (fill, stroke) = crate::panels::current_paints(app); diff --git a/crates/ui-egui/src/state.rs b/crates/ui-egui/src/state.rs index f4e90f6d8..bfe63c699 100644 --- a/crates/ui-egui/src/state.rs +++ b/crates/ui-egui/src/state.rs @@ -483,6 +483,11 @@ pub struct UiState { /// swatches) or "" (none) (`ui.colorGuideLimit`). #[serde(default)] pub color_guide_limit: String, + /// Color Guide panel: the base color, set by a color chosen in the Color panel, the Swatches + /// panel or the Color Picker and by the panel's base chip (none: the current color). Not + /// saved. + #[serde(skip)] + pub color_guide_base: Option, /// Align panel: the Align To choice, Selection or Artboard, which Object → Align and the align /// buttons follow ([`crate::panels::align::with_align_to`]). #[serde(default, deserialize_with = "crate::panels::align::deserialize_align_to")] @@ -855,6 +860,7 @@ impl Default for UiState { library_panels: vec![], flattener_preview: Default::default(), color_guide_limit: String::new(), + color_guide_base: None, align_to: Default::default(), align_spacing: 0.0, color_mode: None,