forked from 1b-agent/opencadstudio-upstream
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:
1 parent
5a638f243a
commit
7ea1aef95e
4 files changed
+109
No files matched your search
@@ -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).
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user