From 6e05c7e2e5337ef4c0d1bfd80c1149260756ebdc Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 20:15:53 +0000 Subject: [PATCH] Select Color: one fixed colour book folder instead of a folder list setting The color_book_dirs setting is gone. Colour books live in color_books in the config folder (book::folder()), like the other fixed locations; Options > Files shows it through Folders::color_books. read_all() and load_from_dialog() use that folder directly. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013rGmDUNr1hUf4zo1X3dak8 --- src/app/mod.rs | 6 ++-- src/app/settings.rs | 14 --------- src/app/update/file.rs | 5 --- src/app/update/mod.rs | 14 +++------ src/app/view/modal.rs | 3 +- src/ui/color_select/book.rs | 62 ++++++++++++++++++------------------- src/ui/window/options.rs | 15 +++++---- 7 files changed, 47 insertions(+), 72 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index 88d8acea4..fe90c4e7a 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1067,10 +1067,9 @@ pub(super) struct OpenCADStudio { // ── Floating panel windows ──────────────────────────────────────────── /// The open Select Color panel, if any. color_picker: Option, - /// The built-in colour books and those in `color_book_dirs`, read - /// lazily when the Select Color panel opens. + /// The built-in colour book and those in the colour book folder, read + /// lazily when the Select Color panel first opens. color_books: std::sync::Arc>, - color_book_dirs: Vec, color_books_read: bool, /// Recently committed real colours, newest first. /// ACI and True Color remain semantically distinct even when their RGB matches. @@ -4793,7 +4792,6 @@ impl OpenCADStudio { web_autosave_clear_after: Vec::new(), color_picker: None, color_books: Default::default(), - color_book_dirs: Vec::new(), color_books_read: false, active_modal: None, hyperlink_editor_handles: Vec::new(), diff --git a/src/app/settings.rs b/src/app/settings.rs index 5a2d5b350..a63453fb1 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -636,10 +636,6 @@ pub struct UserSettings { /// Blocks palette: library folders or drawings, last used first. #[serde(default)] pub block_libraries: Vec, - /// Folders searched for `.acb` colour books. Books loaded in the Select - /// Color panel are copied into the first one. - #[serde(default = "default_color_book_dirs")] - pub color_book_dirs: Vec, /// Blocks palette view: 0 extra large, 1 large, 2 medium, 3 small icons, /// 4 details, 5 list. #[serde(default = "default_block_view")] @@ -801,15 +797,6 @@ fn default_grid_major() -> u32 { 5 } -/// One folder in the config directory; none on the web, which has no folders. -fn default_color_book_dirs() -> Vec { - #[cfg(not(target_arch = "wasm32"))] - if let Some(dir) = crate::config::config_dir() { - return vec![dir.join("color_books").display().to_string()]; - } - Vec::new() -} - fn default_true() -> bool { true } @@ -973,7 +960,6 @@ impl Default for UserSettings { block_recent: Vec::new(), block_favorites: Vec::new(), block_libraries: Vec::new(), - color_book_dirs: default_color_book_dirs(), block_palette_view: 1, block_insert: BlockInsertOptions::default(), block_mru_list: 50, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index a3ef47a36..5405968bc 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -868,7 +868,6 @@ impl OpenCADStudio { block_recent: self.block_palette.recent.clone(), block_favorites: self.block_palette.favorites.clone(), block_libraries: self.block_palette.libraries.clone(), - color_book_dirs: self.color_book_dirs.clone(), block_palette_view: self.block_palette.view as u8, block_insert: self.block_palette.options.clone(), block_mru_list: self.block_mru_list, @@ -1047,10 +1046,6 @@ impl OpenCADStudio { self.block_palette.recent = s.block_recent.clone(); self.block_palette.favorites = s.block_favorites.clone(); self.block_palette.libraries = s.block_libraries.clone(); - if self.color_book_dirs != s.color_book_dirs { - self.color_book_dirs = s.color_book_dirs.clone(); - self.color_books_read = false; - } self.block_palette.view = crate::ui::window::block_palette::ViewMode::from_u8(s.block_palette_view); self.block_palette.set_options(s.block_insert.clone()); diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index d0e3cad1d..f26586359 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -11935,9 +11935,7 @@ impl OpenCADStudio { self.update(Message::ColorWindowPick(color, name)) } Some(crate::ui::color_select::Outcome::LoadBook) => Task::perform( - crate::ui::color_select::book::load_from_dialog( - self.color_book_dirs.first().cloned(), - ), + crate::ui::color_select::book::load_from_dialog(), Message::ColorBookLoaded, ), Some(crate::ui::color_select::Outcome::Cancel) => { @@ -12070,16 +12068,14 @@ impl OpenCADStudio { document.layers.get(layer).map(|layer| layer.color) } - /// Read the built-in colour books and every `.acb` in the colour book - /// folders, once until the folders change. A book in a folder replaces a - /// built-in one of the same name. + /// Read the built-in colour book and every `.acb` in the colour book + /// folder, once per session. A book in the folder replaces a built-in + /// one of the same name. fn read_color_books(&mut self) { if std::mem::replace(&mut self.color_books_read, true) { return; } - self.color_books = std::sync::Arc::new(crate::ui::color_select::book::read_all( - &self.color_book_dirs, - )); + self.color_books = std::sync::Arc::new(crate::ui::color_select::book::read_all()); } /// Colour the selected objects (or set the current colour when nothing diff --git a/src/app/view/modal.rs b/src/app/view/modal.rs index 12671c570..007c5e4ec 100644 --- a/src/app/view/modal.rs +++ b/src/app/view/modal.rs @@ -373,6 +373,8 @@ impl OpenCADStudio { .map(|_| std::env::temp_dir().display().to_string()), fonts: crate::io::font_repo::fonts_dir() .map(|p| p.display().to_string()), + color_books: crate::ui::color_select::book::folder() + .map(|p| p.display().to_string()), } } #[cfg(target_arch = "wasm32")] @@ -381,7 +383,6 @@ impl OpenCADStudio { } }, &self.qnew_template, - &self.color_book_dirs, self.double_click_block_refedit, self.double_click_block_attedit, self.cursor_type, diff --git a/src/ui/color_select/book.rs b/src/ui/color_select/book.rs index 4a8966403..cff68b5b6 100644 --- a/src/ui/color_select/book.rs +++ b/src/ui/color_select/book.rs @@ -77,42 +77,45 @@ pub fn builtin() -> impl Iterator { parse(include_str!("../../../assets/color_books/ral-classic.acb")).into_iter() } -/// The built-in book plus every `.acb` file in `dirs`, folder by folder in +/// Where colour books are kept: `color_books` in the config folder. The +/// web has no folders. +#[cfg(not(target_arch = "wasm32"))] +pub fn folder() -> Option { + crate::config::config_dir().map(|dir| dir.join("color_books")) +} + +/// The built-in book plus every `.acb` file in the colour book folder, in /// file-name order. A book replaces an earlier one of the same name. -pub fn read_all(dirs: &[String]) -> Vec { +pub fn read_all() -> Vec { #[cfg_attr(target_arch = "wasm32", allow(unused_mut))] let mut books: Vec<_> = builtin().collect(); - // Browsers have no folders. - #[cfg(target_arch = "wasm32")] - let _ = dirs; #[cfg(not(target_arch = "wasm32"))] - for book in dirs - .iter() - .flat_map(|dir| { - let mut files: Vec<_> = std::fs::read_dir(dir) - .into_iter() - .flatten() - .filter_map(|entry| entry.ok().map(|entry| entry.path())) - .filter(|path| { - path.extension() - .is_some_and(|ext| ext.eq_ignore_ascii_case("acb")) - }) - .collect(); - files.sort(); - files - }) - .filter_map(|path| std::fs::read_to_string(path).ok()) - .filter_map(|text| parse(&text).ok()) - { - add_or_replace(&mut books, book); + if let Some(dir) = folder() { + let mut files: Vec<_> = std::fs::read_dir(dir) + .into_iter() + .flatten() + .filter_map(|entry| entry.ok().map(|entry| entry.path())) + .filter(|path| { + path.extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("acb")) + }) + .collect(); + files.sort(); + for book in files + .into_iter() + .filter_map(|path| std::fs::read_to_string(path).ok()) + .filter_map(|text| parse(&text).ok()) + { + add_or_replace(&mut books, book); + } } books } /// Ask for an `.acb` file and read it. On desktop the file is copied into -/// `folder`, the first colour book folder, so it stays when the original -/// moves; the web keeps the book for the session only. -pub async fn load_from_dialog(folder: Option) -> Result { +/// the colour book folder, so it stays when the original moves; the web +/// keeps the book for the session only. +pub async fn load_from_dialog() -> Result { let file = crate::sys::file_dialog() .add_filter(crate::t!("Color book").as_ref(), &["acb", "ACB"]) .pick_file() @@ -121,14 +124,11 @@ pub async fn load_from_dialog(folder: Option) -> Result, + /// Where `.acb` colour books are kept and loaded ones copied to. + pub color_books: Option, } /// Values read from the current drawing's header rather than from preferences. @@ -212,7 +214,6 @@ pub fn view_window<'a>( drawing_prefs: DrawingPrefs, folders: Folders, qnew_template: &'a str, - color_book_dirs: &'a [String], double_click_block_refedit: bool, double_click_block_attedit: bool, cursor_type: CursorType, @@ -1791,13 +1792,11 @@ pub fn view_window<'a>( folder_row(crate::t!("Autosave files"), folders.autosave.clone()), Space::new().height(12), folder_row(crate::t!("Fonts"), folders.fonts.clone()), - // Where `.acb` colour books are found (none on the web). - color_book_dirs.iter().fold(column![], |rows, dir| rows - .push(Space::new().height(12)) - .push(folder_row( - crate::t!("Color book locations"), - Some(dir.clone()) - ))), + Space::new().height(12), + folder_row( + crate::t!("Color book locations"), + folders.color_books.clone() + ), Space::new().height(16), text(crate::t!("Default template for new drawings")).size(12), Space::new().height(4),