Add a Files page, and links out to the editors that own their own dialogs

The application has no support-file search path — the four folders it uses
are functions returning fixed paths, not settings. Rather than build a Files
page that pretends otherwise, this one answers the question people actually
open it to ask: where does this thing keep my plot styles. Each row shows the
location and opens it in the file manager, and a row whose path the platform
could not give says so with its button disabled.

General gains buttons through to the plugin manager, the keyboard shortcut
editor and the alias editor. Those three have good dialogs of their own and
are not absorbed; Options simply stops being a place you cannot reach them
from.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
PanosandClaude Opus 5 committed 2026-09-10 08:45:20 +03:00
1 parent 5a638f243a
commit 7ea1aef95e
4 files changed
+109

No files matched your search

+2
View File
@@ -2044,6 +2044,8 @@ pub enum Message {
UcsIconAtOriginChanged(bool),
/// Toggle selection cycling from Options; the status-bar pill toggles the same flag.
SelectionCyclingChanged(bool),
/// Reveal one of the application's own folders in the system file manager.
OpenFolder(String),
/// Change isolines per surface in the current drawing (ISOLINES).
IsolinesChanged(i16),
/// Toggle silhouette edges in the current drawing (DISPSILH).
+2
View File
@@ -6363,6 +6363,8 @@ impl OpenCADStudio {
Task::none()
}
Message::OpenFolder(path) => crate::sys::open_url(&path, None),
Message::PickDragRectToggled(rectangle) => {
self.pick_drag_rect = rectangle;
self.persist_settings_if_changed();
+11
View File
@@ -230,6 +230,17 @@ impl OpenCADStudio {
.map_or(1, |h| h.show_solid_history),
}
},
crate::ui::window::options::Folders {
config: crate::config::config_dir()
.map(|p| p.display().to_string()),
plot_styles: crate::io::plot_style::plot_styles_dir()
.ok()
.map(|p| p.display().to_string()),
plugins: crate::plugin::external::plugins_dir()
.map(|p| p.display().to_string()),
autosave: crate::config::config_dir()
.map(|_| std::env::temp_dir().display().to_string()),
},
self.double_click_block_refedit,
self.double_click_block_attedit,
self.cursor_type,
+94
View File
@@ -25,6 +25,7 @@ const DIALOG_HEIGHT: f32 = 620.0;
pub enum OptionsTab {
#[default]
General,
Files,
OpenAndSave,
Display,
Drafting,
@@ -74,6 +75,18 @@ pub struct AppPrefs {
pub ucs_icon_at_origin: bool,
}
/// The fixed locations the Files page lists.
///
/// `None` where the platform could not give one — the row then says so and
/// its button is disabled rather than opening nothing.
#[derive(Clone, Default)]
pub struct Folders {
pub config: Option<String>,
pub plot_styles: Option<String>,
pub plugins: Option<String>,
pub autosave: Option<String>,
}
/// Values read from the current drawing's header rather than from preferences.
///
/// These are saved in the DWG, so they follow the drawing rather than the
@@ -142,6 +155,7 @@ pub fn view_window<'a>(
prefs: AppPrefs,
snap_angle_input: &'a str,
drawing_prefs: DrawingPrefs,
folders: Folders,
double_click_block_refedit: bool,
double_click_block_attedit: bool,
cursor_type: CursorType,
@@ -259,6 +273,38 @@ pub fn view_window<'a>(
]
.spacing(12)
.align_y(iced::Center),
Space::new().height(24),
text(crate::t!("Applications")).size(15),
Space::new().height(10),
row![
text(crate::t!("Installed plugins and their sources")).size(12).width(Fill),
button(text(crate::t!("Plugins…")).size(11))
.on_press(Message::PluginManagerOpen)
.padding([4, 10])
.style(button::secondary),
]
.spacing(10)
.align_y(iced::Center),
Space::new().height(10),
row![
text(crate::t!("Keyboard shortcuts")).size(12).width(Fill),
button(text(crate::t!("Keyboard Shortcuts…")).size(11))
.on_press(Message::ShortcutsPanelOpen)
.padding([4, 10])
.style(button::secondary),
]
.spacing(10)
.align_y(iced::Center),
Space::new().height(10),
row![
text(crate::t!("Command aliases")).size(12).width(Fill),
button(text(crate::t!("Command Aliases…")).size(11))
.on_press(Message::AliasEditorOpen)
.padding([4, 10])
.style(button::secondary),
]
.spacing(10)
.align_y(iced::Center),
]
.spacing(0)
.width(sizing.width);
@@ -1464,10 +1510,57 @@ pub fn view_window<'a>(
let modeling = modeling.spacing(0).width(sizing.width);
// The application has no support-file search path, so this page does not
// pretend to offer one. It shows where things actually live and opens the
// folder — which is the question people are really asking when they go
// looking for a Files page.
let folder_row = |label: std::borrow::Cow<'a, str>, path: Option<String>| {
let shown = path.clone().unwrap_or_else(|| crate::t!("Not available").into_owned());
let mut open = button(text(crate::t!("Open folder")).size(11))
.padding([4, 10])
.style(button::secondary);
if let Some(path) = path {
open = open.on_press(Message::OpenFolder(path));
}
row![
column![
text(label).size(12),
text(shown).size(11),
]
.spacing(2)
.width(Fill),
open,
]
.spacing(10)
.align_y(iced::Center)
};
let files = column![
text(crate::t!("Files")).size(15),
Space::new().height(6),
text(crate::t!(
"Where the application keeps its own files. These locations are fixed."
))
.size(11)
.width(sizing.width),
Space::new().height(16),
folder_row(crate::t!("Configuration"), folders.config.clone()),
Space::new().height(12),
folder_row(crate::t!("Plot styles"), folders.plot_styles.clone()),
Space::new().height(12),
folder_row(crate::t!("Plugins"), folders.plugins.clone()),
Space::new().height(12),
folder_row(crate::t!("Autosave files"), folders.autosave.clone()),
]
.spacing(0)
.width(sizing.width);
let content: Element<'a, Message> = match active_tab {
OptionsTab::General => general.into(),
OptionsTab::Display => display_element.into(),
OptionsTab::Selection => selection.into(),
OptionsTab::Files => files.into(),
OptionsTab::OpenAndSave => open_and_save.into(),
OptionsTab::Drafting => drafting.into(),
OptionsTab::Modeling => modeling.into(),
@@ -1488,6 +1581,7 @@ pub fn view_window<'a>(
};
let tabs = column![
tab_button(crate::t!("General"), OptionsTab::General),
tab_button(crate::t!("Files"), OptionsTab::Files),
tab_button(crate::t!("Open and Save"), OptionsTab::OpenAndSave),
tab_button(crate::t!("Display"), OptionsTab::Display),
tab_button(crate::t!("Drafting"), OptionsTab::Drafting),