forked from 1b-agent/opencadstudio-upstream
feat(plugin): enable/disable plugins from the Plugin Manager
The manager was a read-only inventory. Each plugin now has an Enable/Disable toggle: a disabled plugin keeps its manifest listed but drops its ribbon tab and command dispatch. The disabled-id set persists in settings.txt (disabled_plugins=) and the ribbon rebuilds on toggle. Part of the #100 extensibility epic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
195415af84
commit
844069b4ef
9 files changed
+157
-23
No files matched your search
@@ -293,6 +293,10 @@ pub(super) struct OpenCADStudio {
|
||||
modal_drag_last: Option<Point>,
|
||||
/// True while the modal title bar is held (a drag is in progress).
|
||||
modal_dragging: bool,
|
||||
/// Plugin ids the user turned off in the Plugin Manager. Disabled plugins
|
||||
/// keep their manifest listed but drop their ribbon tab and command
|
||||
/// dispatch. Persisted via [`settings::UserSettings::disabled_plugins`].
|
||||
disabled_plugins: rustc_hash::FxHashSet<String>,
|
||||
/// New-release notification window — opened on startup when the
|
||||
/// GitHub releases API reports a newer version than this build.
|
||||
/// First-launch "make Open CAD Studio the default for .dwg/.dxf?" prompt
|
||||
@@ -1018,6 +1022,8 @@ pub enum Message {
|
||||
PluginManagerOpen,
|
||||
#[allow(dead_code)]
|
||||
PluginManagerClose,
|
||||
/// Enable (`true`) or disable (`false`) the plugin with this id.
|
||||
SetPluginEnabled(String, bool),
|
||||
// ── Quick Select / Select Similar ───────────────────────────────────
|
||||
/// Extend the current selection with every entity in the active
|
||||
/// layout that matches a selected entity by (type, layer).
|
||||
@@ -1428,6 +1434,7 @@ impl OpenCADStudio {
|
||||
modal_offset: iced::Vector::ZERO,
|
||||
modal_drag_last: None,
|
||||
modal_dragging: false,
|
||||
disabled_plugins: rustc_hash::FxHashSet::default(),
|
||||
default_assoc_prompted: false,
|
||||
update_notice_version: None,
|
||||
update_notice_body: None,
|
||||
|
||||
+15
-1
@@ -74,6 +74,10 @@ pub struct UserSettings {
|
||||
/// prompt has already been shown. Set once the user answers (either way),
|
||||
/// so we never nag again on subsequent launches.
|
||||
pub default_assoc_prompted: bool,
|
||||
/// Ids of plugins the user turned off in the Plugin Manager. Disabled
|
||||
/// plugins keep their manifest listed but drop their ribbon tab and command
|
||||
/// dispatch.
|
||||
pub disabled_plugins: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for UserSettings {
|
||||
@@ -96,6 +100,7 @@ impl Default for UserSettings {
|
||||
SnapType::Nearest,
|
||||
],
|
||||
default_assoc_prompted: false,
|
||||
disabled_plugins: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +135,14 @@ impl UserSettings {
|
||||
"osnap" => s.snap_enabled = val == "1",
|
||||
"otrack" => s.otrack = val == "1",
|
||||
"default_assoc_prompted" => s.default_assoc_prompted = val == "1",
|
||||
"disabled_plugins" => {
|
||||
s.disabled_plugins = val
|
||||
.split(',')
|
||||
.map(|t| t.trim())
|
||||
.filter(|t| !t.is_empty())
|
||||
.map(|t| t.to_string())
|
||||
.collect();
|
||||
}
|
||||
"snap_modes" => {
|
||||
let modes: Vec<SnapType> =
|
||||
val.split(',').filter_map(|t| snap_from_id(t.trim())).collect();
|
||||
@@ -155,7 +168,7 @@ impl UserSettings {
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
let body = format!(
|
||||
"dyn={}\northo={}\npolar={}\npolar_increment_deg={}\ngrid={}\nosnap={}\notrack={}\ndefault_assoc_prompted={}\nsnap_modes={}\n",
|
||||
"dyn={}\northo={}\npolar={}\npolar_increment_deg={}\ngrid={}\nosnap={}\notrack={}\ndefault_assoc_prompted={}\nsnap_modes={}\ndisabled_plugins={}\n",
|
||||
b(self.dyn_input),
|
||||
b(self.ortho),
|
||||
b(self.polar),
|
||||
@@ -165,6 +178,7 @@ impl UserSettings {
|
||||
b(self.otrack),
|
||||
b(self.default_assoc_prompted),
|
||||
modes,
|
||||
self.disabled_plugins.join(","),
|
||||
);
|
||||
let _ = std::fs::write(path, body);
|
||||
}
|
||||
|
||||
@@ -141,6 +141,11 @@ impl OpenCADStudio {
|
||||
otrack: self.snapper.otrack_enabled,
|
||||
snap_modes: super::settings::UserSettings::modes_from(self.snapper.enabled.iter()),
|
||||
default_assoc_prompted: self.default_assoc_prompted,
|
||||
disabled_plugins: {
|
||||
let mut v: Vec<String> = self.disabled_plugins.iter().cloned().collect();
|
||||
v.sort();
|
||||
v
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +160,22 @@ impl OpenCADStudio {
|
||||
self.snapper.otrack_enabled = s.otrack;
|
||||
self.snapper.enabled = s.snap_modes.iter().copied().collect();
|
||||
self.default_assoc_prompted = s.default_assoc_prompted;
|
||||
self.disabled_plugins = s.disabled_plugins.iter().cloned().collect();
|
||||
self.rebuild_ribbon_modules();
|
||||
}
|
||||
|
||||
/// Rebuild the ribbon's tab list from the registry, dropping the tabs of any
|
||||
/// disabled plugins. Call after `disabled_plugins` changes.
|
||||
pub(super) fn rebuild_ribbon_modules(&mut self) {
|
||||
let modules =
|
||||
crate::plugin::ribbon_modules_enabled(&self.disabled_plugins);
|
||||
self.ribbon.set_modules(modules);
|
||||
}
|
||||
|
||||
/// Snapshot of disabled plugin ids — lets the registry skip them while it
|
||||
/// holds a `&mut` borrow of the app via `HostSession`.
|
||||
pub(crate) fn disabled_plugin_ids(&self) -> rustc_hash::FxHashSet<String> {
|
||||
self.disabled_plugins.clone()
|
||||
}
|
||||
|
||||
/// Write preferences to disk only when they differ from the last write,
|
||||
@@ -5432,6 +5453,16 @@ impl OpenCADStudio {
|
||||
self.close_active_modal();
|
||||
Task::none()
|
||||
}
|
||||
Message::SetPluginEnabled(id, enabled) => {
|
||||
if enabled {
|
||||
self.disabled_plugins.remove(&id);
|
||||
} else {
|
||||
self.disabled_plugins.insert(id);
|
||||
}
|
||||
self.rebuild_ribbon_modules();
|
||||
self.persist_settings_if_changed();
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::EnterViewport(handle) => {
|
||||
let i = self.active_tab;
|
||||
|
||||
+4
-1
@@ -1120,7 +1120,10 @@ impl OpenCADStudio {
|
||||
sized(crate::ui::shortcuts::view_window(&self.shortcut_overrides), 720, 520)
|
||||
}
|
||||
super::ModalKind::PluginManager => sized(
|
||||
crate::ui::plugin_manager::view_window(&crate::plugin::installed_manifests()),
|
||||
crate::ui::plugin_manager::view_window(
|
||||
&crate::plugin::installed_manifests(),
|
||||
&self.disabled_plugins,
|
||||
),
|
||||
520,
|
||||
460,
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user