Swatches: the panel menu's Show Recent Colors shows or hides the Recent Colors row (#6617)

This commit is contained in:
Don Omondi
2026-11-12 18:04:20 -05:00
parent 71d717b1da
commit 1900c9429d
6 changed files with 80 additions and 8 deletions
+3 -2
View File
@@ -1,5 +1,6 @@
//! Swatches panel: proxy, Recent Colors, find field, thumbnail grid (15.5 pt tiles on a 17 pt pitch)
//! or list, colour groups as folders, None/Registration first, bottom bar and panel menu.
//! Swatches panel: proxy, Recent Colors (hidden by the panel menu's Show Recent Colors), find
//! field, thumbnail grid (15.5 pt tiles on a 17 pt pitch) or list, colour groups as folders,
//! None/Registration first, bottom bar and panel menu.
//!
//! Swatches drag to reorder, into and out of colour groups (`swatch.move`) and onto art (the active
//! proxy's paint command with the object's id) and onto the Gradient panel's ramp; a Fill/Stroke
@@ -182,6 +182,10 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
if menu_item(ui, tl!("Show Find Field"), true, find) {
set_pstate(ui.ctx(), "swatch-show-find", !find);
}
let recent = app.ui.swatches_show_recent_colors;
if menu_item(ui, tl!("Show Recent Colors"), true, recent) {
app.ui.swatches_show_recent_colors = !recent;
}
ui.separator();
if menu_item(ui, tl!("Swatch Options…"), opts.is_some(), false)
&& let Some(n) = opts
+7 -5
View File
@@ -31,12 +31,14 @@ 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, 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)}));
// becomes the Color Guide's base color. The panel menu's Show Recent Colors hides the row.
if app.ui.swatches_show_recent_colors {
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);
}
widgets::divider(ui);
widgets::subheader(ui, tl!("Swatch Tiles"));
let query = if pstate(ui.ctx(), "swatch-show-find") { widgets::search_field(ui, find_id(), tl!("Find")) } else { String::new() };
let items = entries(app, kind, &query);
@@ -901,3 +901,61 @@ fn lab_spot_tiles_show_the_colour_the_spot_colors_options_pick() {
assert_eq!(tile(&app), app.session.active().unwrap().doc.global_color("Ink").unwrap());
assert!(matches!(tile(&app), Color::Cmyk { .. }));
}
/// One headless frame of the panel menu; returns its painted labels.
fn menu_frame(app: &mut VectorcraftApp, ctx: &egui::Context, events: Vec<Event>) -> Vec<(String, Rect)> {
let raw = egui::RawInput { screen_rect: Some(Rect::from_min_size(Pos2::ZERO, vec2(236.0, 700.0))), events, ..Default::default() };
let mut out = ctx.run_ui(raw, |ui| menu(app, ui));
out.textures_delta.clear();
crate::tests_removeanchors::shapes_text(&out.shapes.iter().map(|c| c.shape.clone()).collect::<Vec<_>>())
}
/// Click the panel menu's item `label`.
fn click_menu_item(app: &mut VectorcraftApp, ctx: &egui::Context, label: &str) {
let labels = menu_frame(app, ctx, vec![]);
let at = labels.iter().find(|(t, _)| t.trim() == label).map(|(_, r)| r.center()).unwrap_or_else(|| panic!("no {label} in the menu"));
let button = |pressed| Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE };
menu_frame(app, ctx, vec![Event::PointerMoved(at), button(true)]);
menu_frame(app, ctx, vec![button(false)]);
}
/// The panel menu's Show Recent Colors hides and shows the panel's Recent Colors row (#6617):
/// checked by default, applied colors still join the list while the row is hidden, and the Color
/// panel keeps its own row and setting.
#[test]
fn show_recent_colors_hides_and_shows_the_swatches_row() {
let mut app = app();
app.run("paint.setFill", json!({"color": "#ff0000"})).unwrap();
let ctx = context();
let menu_ctx = context();
// The first recent chip, if the panel draws one (the second frame's answer counts, since egui
// also answers for a widget the frame before drew).
let chip = |app: &mut VectorcraftApp| {
let mut chip = None;
for _ in 0..2 {
let screen_rect = Some(Rect::from_min_size(Pos2::ZERO, vec2(280.0, 700.0)));
let mut out = ctx.run_ui(egui::RawInput { screen_rect, ..Default::default() }, |ui| {
show(app, ui);
chip = ctx.read_response(ui.scope_id().with(("recent", 0usize))).map(|r| r.rect);
});
out.textures_delta.clear();
}
chip
};
assert!(chip(&mut app).is_some(), "the row shows by default");
click_menu_item(&mut app, &menu_ctx, "✓ Show Recent Colors");
assert!(!app.ui.swatches_show_recent_colors);
assert!(chip(&mut app).is_none(), "unchecked, the row is hidden");
app.run("paint.setFill", json!({"color": "#00ff00"})).unwrap();
assert_eq!(app.session.recent_colors.first().map(|c| c.to_hex()).as_deref(), Some("#00ff00"), "colors still join the list");
assert_eq!(app.run("ui.colorPanel", json!({})).unwrap()["recentColors"], true, "the Color panel keeps its setting");
click_menu_item(&mut app, &menu_ctx, "Show Recent Colors");
assert!(chip(&mut app).is_some(), "checking the item shows the row again");
// The app keeps it with the preferences; a saved value that isn't true or false reads as on.
let saved = |v: Value| {
let mut prefs = serde_json::to_value(crate::UiState::default()).unwrap();
prefs["swatches_show_recent_colors"] = v;
serde_json::from_value::<crate::UiState>(prefs).unwrap().swatches_show_recent_colors
};
assert_eq!((saved(json!(false)), saved(json!(true)), saved(json!("no"))), (false, true, true));
}
+5
View File
@@ -699,6 +699,10 @@ pub struct UiState {
/// recent colors keeps filling while the row is hidden.
#[serde(default = "yes", deserialize_with = "crate::panels::color::deserialize_show_recent_colors")]
pub color_show_recent_colors: bool,
/// Swatches panel: Show Recent Colors in its panel menu, which draws the panel's Recent Colors
/// row (#6617; read as [`Self::color_show_recent_colors`] is). Separate from the Color panel's.
#[serde(default = "yes", deserialize_with = "crate::panels::color::deserialize_show_recent_colors")]
pub swatches_show_recent_colors: bool,
/// The SVG Options chosen last (`svg` object of the export/save commands; null: never used).
#[serde(default)]
pub svg_options: Value,
@@ -1148,6 +1152,7 @@ impl Default for UiState {
color_mode: None,
color_hide_options: false,
color_show_recent_colors: true,
swatches_show_recent_colors: true,
svg_options: Value::Null,
place_link: true,
dialog_file: None,
File diff suppressed because one or more lines are too long